alicezetion 1.5.7 → 1.5.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. package/.cache/replit/__replit_disk_meta.json +1 -1
  2. package/.cache/replit/nix/env.json +1 -1
  3. package/index.js +489 -526
  4. package/leiamnash/addExternalModule.js +15 -19
  5. package/leiamnash/addUserToGroup.js +77 -113
  6. package/leiamnash/changeAdminStatus.js +47 -79
  7. package/leiamnash/changeArchivedStatus.js +41 -55
  8. package/leiamnash/changeBio.js +64 -77
  9. package/leiamnash/changeBlockedStatus.js +36 -47
  10. package/leiamnash/changeGroupImage.js +105 -129
  11. package/leiamnash/changeNickname.js +43 -59
  12. package/leiamnash/changeThreadColor.js +61 -71
  13. package/leiamnash/changeThreadEmoji.js +41 -55
  14. package/leiamnash/chat.js +324 -459
  15. package/leiamnash/createNewGroup.js +70 -86
  16. package/leiamnash/createPoll.js +59 -71
  17. package/leiamnash/deleteMessage.js +44 -56
  18. package/leiamnash/deleteThread.js +42 -56
  19. package/leiamnash/forwardAttachment.js +47 -60
  20. package/leiamnash/forwardMessage.js +0 -0
  21. package/leiamnash/getCurrentUserID.js +7 -7
  22. package/leiamnash/getEmojiUrl.js +27 -29
  23. package/leiamnash/getFriendsList.js +73 -84
  24. package/leiamnash/getThreadHistory.js +537 -645
  25. package/leiamnash/getThreadHistoryDeprecated.js +71 -93
  26. package/leiamnash/getThreadInfo.js +171 -206
  27. package/leiamnash/getThreadInfoDeprecated.js +56 -80
  28. package/leiamnash/getThreadList.js +213 -238
  29. package/leiamnash/getThreadListDeprecated.js +46 -75
  30. package/leiamnash/getThreadPictures.js +59 -79
  31. package/leiamnash/getUserID.js +61 -66
  32. package/leiamnash/getUserInfo.js +66 -72
  33. package/leiamnash/handleFriendRequest.js +46 -61
  34. package/leiamnash/handleMessageRequest.js +47 -65
  35. package/leiamnash/httpGet.js +47 -52
  36. package/leiamnash/httpPost.js +47 -52
  37. package/leiamnash/listen.js +553 -0
  38. package/leiamnash/listenMqtt-Test.js +687 -0
  39. package/leiamnash/listenMqtt.js +685 -789
  40. package/leiamnash/logout.js +68 -75
  41. package/leiamnash/markAsDelivered.js +47 -58
  42. package/leiamnash/markAsRead.js +70 -80
  43. package/leiamnash/markAsReadAll.js +39 -49
  44. package/leiamnash/markAsSeen.js +48 -59
  45. package/leiamnash/muteThread.js +45 -52
  46. package/leiamnash/removeUserFromGroup.js +45 -79
  47. package/leiamnash/resolvePhotoUrl.js +36 -45
  48. package/leiamnash/searchForThread.js +42 -53
  49. package/leiamnash/sendTypingIndicator.js +70 -103
  50. package/leiamnash/setMessageReaction.js +103 -117
  51. package/leiamnash/setPostReaction.js +63 -76
  52. package/leiamnash/setTitle.js +70 -86
  53. package/leiamnash/threadColors.js +41 -57
  54. package/leiamnash/unfriend.js +42 -52
  55. package/leiamnash/unsendMessage.js +39 -49
  56. package/package.json +73 -71
  57. package/utils.js +1198 -1356
package/leiamnash/chat.js CHANGED
@@ -1,459 +1,324 @@
1
- "use strict";
2
-
3
- var utils = require("../utils");
4
- var log = require("npmlog");
5
- var bluebird = require("bluebird");
6
-
7
- var allowedProperties = {
8
- attachment: true,
9
- url: true,
10
- sticker: true,
11
- emoji: true,
12
- emojiSize: true,
13
- body: true,
14
- mentions: true,
15
- location: true,
16
- };
17
-
18
- module.exports = function (defaultFuncs, api, ctx) {
19
- function uploadAttachment(attachments, callback) {
20
- var uploads = [];
21
-
22
- // create an array of promises
23
- for (var i = 0; i < attachments.length; i++) {
24
- if (!utils.isReadableStream(attachments[i])) {
25
- throw {
26
- error:
27
- "Attachment should be a readable stream and not " +
28
- utils.getType(attachments[i]) +
29
- "."
30
- };
31
- }
32
-
33
- var form = {
34
- upload_1024: attachments[i],
35
- voice_clip: "true"
36
- };
37
-
38
- uploads.push(
39
- defaultFuncs
40
- .postFormData(
41
- "https://upload.facebook.com/ajax/mercury/upload.php",
42
- ctx.jar,
43
- form,
44
- {}
45
- )
46
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
47
- .then(function (resData) {
48
- if (resData.error) {
49
- throw resData;
50
- }
51
-
52
- // We have to return the data unformatted unless we want to change it
53
- // back in sendMessage.
54
- return resData.payload.metadata[0];
55
- })
56
- );
57
- }
58
-
59
- // resolve all promises
60
- bluebird
61
- .all(uploads)
62
- .then(function (resData) {
63
- callback(null, resData);
64
- })
65
- .catch(function (err) {
66
- log.error("uploadAttachment", err);
67
- return callback(err);
68
- });
69
- }
70
-
71
- function getUrl(url, callback) {
72
- var form = {
73
- image_height: 960,
74
- image_width: 960,
75
- uri: url
76
- };
77
-
78
- defaultFuncs
79
- .post(
80
- "https://www.facebook.com/message_share_attachment/fromURI/",
81
- ctx.jar,
82
- form
83
- )
84
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
85
- .then(function (resData) {
86
- if (resData.error) {
87
- return callback(resData);
88
- }
89
-
90
- if (!resData.payload) {
91
- return callback({ error: "Invalid url" });
92
- }
93
-
94
- callback(null, resData.payload.share_data.share_params);
95
- })
96
- .catch(function (err) {
97
- log.error("getUrl", err);
98
- return callback(err);
99
- });
100
- }
101
-
102
- function sendContent(form, threadID, isSingleUser, messageAndOTID, callback) {
103
- // There are three cases here:
104
- // 1. threadID is of type array, where we're starting a new group chat with users
105
- // specified in the array.
106
- // 2. User is sending a message to a specific user.
107
- // 3. No additional form params and the message goes to an existing group chat.
108
- if (utils.getType(threadID) === "Array") {
109
- for (var i = 0; i < threadID.length; i++) {
110
- form["specific_to_list[" + i + "]"] = "fbid:" + threadID[i];
111
- }
112
- form["specific_to_list[" + threadID.length + "]"] = "fbid:" + ctx.userID;
113
- form["client_thread_id"] = "root:" + messageAndOTID;
114
- log.info("sendMessage", "Sending message to multiple users: " + threadID);
115
- } else {
116
- // This means that threadID is the id of a user, and the chat
117
- // is a single person chat
118
- if (isSingleUser) {
119
- form["specific_to_list[0]"] = "fbid:" + threadID;
120
- form["specific_to_list[1]"] = "fbid:" + ctx.userID;
121
- form["other_user_fbid"] = threadID;
122
- } else {
123
- form["thread_fbid"] = threadID;
124
- }
125
- }
126
-
127
- if (ctx.globalOptions.pageID) {
128
- form["author"] = "fbid:" + ctx.globalOptions.pageID;
129
- form["specific_to_list[1]"] = "fbid:" + ctx.globalOptions.pageID;
130
- form["creator_info[creatorID]"] = ctx.userID;
131
- form["creator_info[creatorType]"] = "direct_admin";
132
- form["creator_info[labelType]"] = "sent_message";
133
- form["creator_info[pageID]"] = ctx.globalOptions.pageID;
134
- form["request_user_id"] = ctx.globalOptions.pageID;
135
- form["creator_info[profileURI]"] =
136
- "https://www.facebook.com/profile.php?id=" + ctx.userID;
137
- }
138
-
139
- defaultFuncs
140
- .post("https://www.facebook.com/messaging/send/", ctx.jar, form)
141
- .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
142
- .then(function (resData) {
143
- if (!resData) {
144
- return callback({ error: "Send message failed." });
145
- }
146
-
147
- if (resData.error) {
148
- if (resData.error === 1545012) {
149
- log.warn(
150
- "sendMessage",
151
- "Got error 1545012. This might mean that you're not part of the conversation " +
152
- threadID
153
- );
154
- }
155
- return callback(resData);
156
- }
157
-
158
- var messageInfo = resData.payload.actions.reduce(function (p, v) {
159
- return (
160
- {
161
- threadID: v.thread_fbid,
162
- messageID: v.message_id,
163
- timestamp: v.timestamp
164
- } || p
165
- );
166
- }, null);
167
-
168
- return callback(null, messageInfo);
169
- })
170
- .catch(function (err) {
171
- log.error("sendMessage", err);
172
- if (utils.getType(err) == "Object" && err.error === "Not logged in.") {
173
- ctx.loggedIn = false;
174
- }
175
- return callback(err);
176
- });
177
- }
178
-
179
- function send(form, threadID, messageAndOTID, callback, isGroup) {
180
- // We're doing a query to this to check if the given id is the id of
181
- // a user or of a group chat. The form will be different depending
182
- // on that.
183
- if (utils.getType(threadID) === "Array") {
184
- sendContent(form, threadID, false, messageAndOTID, callback);
185
- } else {
186
- if (utils.getType(isGroup) != "Boolean") {
187
- api.getUserInfo(threadID, function (err, res) {
188
- if (err) {
189
- return callback(err);
190
- }
191
- sendContent(
192
- form,
193
- threadID,
194
- Object.keys(res).length > 0,
195
- messageAndOTID,
196
- callback
197
- );
198
- });
199
- } else {
200
- sendContent(form, threadID, !isGroup, messageAndOTID, callback);
201
- }
202
- }
203
- }
204
-
205
- function handleUrl(msg, form, callback, cb) {
206
- if (msg.url) {
207
- form["shareable_attachment[share_type]"] = "100";
208
- getUrl(msg.url, function (err, params) {
209
- if (err) {
210
- return callback(err);
211
- }
212
-
213
- form["shareable_attachment[share_params]"] = params;
214
- cb();
215
- });
216
- } else {
217
- cb();
218
- }
219
- }
220
-
221
- function handleLocation(msg, form, callback, cb) {
222
- if (msg.location) {
223
- if (msg.location.latitude == null || msg.location.longitude == null) {
224
- return callback({ error: "location property needs both latitude and longitude" });
225
- }
226
-
227
- form["location_attachment[coordinates][latitude]"] = msg.location.latitude;
228
- form["location_attachment[coordinates][longitude]"] = msg.location.longitude;
229
- form["location_attachment[is_current_location]"] = !!msg.location.current;
230
- }
231
-
232
- cb();
233
- }
234
-
235
- function handleSticker(msg, form, callback, cb) {
236
- if (msg.sticker) {
237
- form["sticker_id"] = msg.sticker;
238
- }
239
- cb();
240
- }
241
-
242
- function handleEmoji(msg, form, callback, cb) {
243
- if (msg.emojiSize != null && msg.emoji == null) {
244
- return callback({ error: "emoji property is empty" });
245
- }
246
- if (msg.emoji) {
247
- if (msg.emojiSize == null) {
248
- msg.emojiSize = "medium";
249
- }
250
- if (
251
- msg.emojiSize != "small" &&
252
- msg.emojiSize != "medium" &&
253
- msg.emojiSize != "large"
254
- ) {
255
- return callback({ error: "emojiSize property is invalid" });
256
- }
257
- if (form["body"] != null && form["body"] != "") {
258
- return callback({ error: "body is not empty" });
259
- }
260
- form["body"] = msg.emoji;
261
- form["tags[0]"] = "hot_emoji_size:" + msg.emojiSize;
262
- }
263
- cb();
264
- }
265
-
266
- function handleAttachment(msg, form, callback, cb) {
267
- if (msg.attachment) {
268
- form["image_ids"] = [];
269
- form["gif_ids"] = [];
270
- form["file_ids"] = [];
271
- form["video_ids"] = [];
272
- form["audio_ids"] = [];
273
-
274
- if (utils.getType(msg.attachment) !== "Array") {
275
- msg.attachment = [msg.attachment];
276
- }
277
-
278
- uploadAttachment(msg.attachment, function (err, files) {
279
- if (err) {
280
- return callback(err);
281
- }
282
-
283
- files.forEach(function (file) {
284
- var key = Object.keys(file);
285
- var type = key[0]; // image_id, file_id, etc
286
- form["" + type + "s"].push(file[type]); // push the id
287
- });
288
- cb();
289
- });
290
- } else {
291
- cb();
292
- }
293
- }
294
-
295
- function handleMention(msg, form, callback, cb) {
296
- if (msg.mentions) {
297
- for (let i = 0; i < msg.mentions.length; i++) {
298
- const mention = msg.mentions[i];
299
-
300
- const tag = mention.tag;
301
- if (typeof tag !== "string") {
302
- return callback({ error: "Mention tags must be strings." });
303
- }
304
-
305
- const offset = msg.body.indexOf(tag, mention.fromIndex || 0);
306
-
307
- if (offset < 0) {
308
- log.warn(
309
- "handleMention",
310
- 'Mention for "' + tag + '" not found in message string.'
311
- );
312
- }
313
-
314
- if (mention.id == null) {
315
- log.warn("handleMention", "Mention id should be non-null.");
316
- }
317
-
318
- const id = mention.id || 0;
319
- form["profile_xmd[" + i + "][offset]"] = offset;
320
- form["profile_xmd[" + i + "][length]"] = tag.length;
321
- form["profile_xmd[" + i + "][id]"] = id;
322
- form["profile_xmd[" + i + "][type]"] = "p";
323
- }
324
- }
325
- cb();
326
- }
327
-
328
- return function sendMessage(msg, threadID, callback, replyToMessage, isGroup) {
329
- typeof isGroup == "undefined" ? isGroup = null : "";
330
- if (
331
- !callback &&
332
- (utils.getType(threadID) === "Function" ||
333
- utils.getType(threadID) === "AsyncFunction")
334
- ) {
335
- return threadID({ error: "Pass a threadID as a second argument." });
336
- }
337
- if (
338
- !replyToMessage &&
339
- utils.getType(callback) === "String"
340
- ) {
341
- replyToMessage = callback;
342
- callback = function () { };
343
- }
344
-
345
- var resolveFunc = function(){};
346
- var rejectFunc = function(){};
347
- var returnPromise = new Promise(function (resolve, reject) {
348
- resolveFunc = resolve;
349
- rejectFunc = reject;
350
- });
351
-
352
- if (!callback) {
353
- callback = function (err, friendList) {
354
- if (err) {
355
- return rejectFunc(err);
356
- }
357
- resolveFunc(friendList);
358
- };
359
- }
360
-
361
- var msgType = utils.getType(msg);
362
- var threadIDType = utils.getType(threadID);
363
- var messageIDType = utils.getType(replyToMessage);
364
-
365
- if (msgType !== "String" && msgType !== "Object") {
366
- return callback({
367
- error:
368
- "Message should be of type string or object and not " + msgType + "."
369
- });
370
- }
371
-
372
- // Changing this to accomodate an array of users
373
- if (
374
- threadIDType !== "Array" &&
375
- threadIDType !== "Number" &&
376
- threadIDType !== "String"
377
- ) {
378
- return callback({
379
- error:
380
- "ThreadID should be of type number, string, or array and not " +
381
- threadIDType +
382
- "."
383
- });
384
- }
385
-
386
- if (replyToMessage && messageIDType !== 'String') {
387
- return callback({
388
- error:
389
- "MessageID should be of type string and not " +
390
- threadIDType +
391
- "."
392
- });
393
- }
394
-
395
- if (msgType === "String") {
396
- msg = { body: msg };
397
- }
398
-
399
- var disallowedProperties = Object.keys(msg).filter(
400
- prop => !allowedProperties[prop]
401
- );
402
- if (disallowedProperties.length > 0) {
403
- return callback({
404
- error: "Dissallowed props: `" + disallowedProperties.join(", ") + "`"
405
- });
406
- }
407
-
408
- var messageAndOTID = utils.generateOfflineThreadingID();
409
-
410
- var form = {
411
- client: "mercury",
412
- action_type: "ma-type:user-generated-message",
413
- author: "fbid:" + ctx.userID,
414
- timestamp: Date.now(),
415
- timestamp_absolute: "Today",
416
- timestamp_relative: utils.generateTimestampRelative(),
417
- timestamp_time_passed: "0",
418
- is_unread: false,
419
- is_cleared: false,
420
- is_forward: false,
421
- is_filtered_content: false,
422
- is_filtered_content_bh: false,
423
- is_filtered_content_account: false,
424
- is_filtered_content_quasar: false,
425
- is_filtered_content_invalid_app: false,
426
- is_spoof_warning: false,
427
- source: "source:chat:web",
428
- "source_tags[0]": "source:chat",
429
- body: msg.body ? msg.body.toString() : "",
430
- html_body: false,
431
- ui_push_phase: "V3",
432
- status: "0",
433
- offline_threading_id: messageAndOTID,
434
- message_id: messageAndOTID,
435
- threading_id: utils.generateThreadingID(ctx.clientID),
436
- "ephemeral_ttl_mode:": "0",
437
- manual_retry_cnt: "0",
438
- has_attachment: !!(msg.attachment || msg.url || msg.sticker),
439
- signatureID: utils.getSignatureID(),
440
- replied_to_message_id: replyToMessage
441
- };
442
-
443
- handleLocation(msg, form, callback, () =>
444
- handleSticker(msg, form, callback, () =>
445
- handleAttachment(msg, form, callback, () =>
446
- handleUrl(msg, form, callback, () =>
447
- handleEmoji(msg, form, callback, () =>
448
- handleMention(msg, form, callback, () =>
449
- send(form, threadID, messageAndOTID, callback, isGroup)
450
- )
451
- )
452
- )
453
- )
454
- )
455
- );
456
-
457
- return returnPromise;
458
- };
459
- };
1
+ /*
2
+
3
+ A L I C E » this project recode by one
4
+ person LeiamNash
5
+ this will only work on
6
+ project alice
7
+
8
+ */
9
+
10
+ "use strict";
11
+
12
+ var utils = require("../utils");
13
+ var log = require("npmlog");
14
+ var bluebird = require("bluebird");
15
+
16
+ var allowedProperties = {
17
+ attachment: true,
18
+ url: true,
19
+ sticker: true,
20
+ emoji: true,
21
+ emojiSize: true,
22
+ body: true,
23
+ mentions: true,
24
+ location: true,
25
+ };
26
+
27
+ module.exports = function(defaultFuncs, api, ctx) {
28
+ function uploadAttachment(attachments, callback) {
29
+ var uploads = [];
30
+
31
+ // create an array of promises
32
+ for (var i = 0; i < attachments.length; i++) {
33
+ if (!utils.isReadableStream(attachments[i])) throw { error: "Attachment should be a readable stream and not " + utils.getType(attachments[i]) + "." };
34
+ var form = {
35
+ upload_1024: attachments[i],
36
+ voice_clip: "true"
37
+ };
38
+
39
+ uploads.push(
40
+ defaultFuncs
41
+ .postFormData("https://upload.facebook.com/ajax/mercury/upload.php", ctx.jar, form, {})
42
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
43
+ .then(function(resData) {
44
+ if (resData.error) throw resData;
45
+ // We have to return the data unformatted unless we want to change it
46
+ // back in sendMessage.
47
+ return resData.payload.metadata[0];
48
+ })
49
+ );
50
+ }
51
+
52
+ // resolve all promises
53
+ bluebird
54
+ .all(uploads)
55
+ .then(resData => callback(null, resData))
56
+ .catch(function(err) {
57
+ log.error("uploadAttachment", err);
58
+ return callback(err);
59
+ });
60
+ }
61
+
62
+ function getUrl(url, callback) {
63
+ var form = {
64
+ image_height: 960,
65
+ image_width: 960,
66
+ uri: url
67
+ };
68
+
69
+ defaultFuncs
70
+ .post("https://www.facebook.com/message_share_attachment/fromURI/", ctx.jar, form)
71
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
72
+ .then(function(resData) {
73
+ if (resData.error) return callback(resData);
74
+ if (!resData.payload) return callback({ error: "Invalid url" });
75
+ callback(null, resData.payload.share_data.share_params);
76
+ })
77
+ .catch(function(err) {
78
+ log.error("getUrl", err);
79
+ return callback(err);
80
+ });
81
+ }
82
+
83
+ function sendContent(form, threadID, isSingleUser, messageAndOTID, callback) {
84
+ // There are three cases here:
85
+ // 1. threadID is of type array, where we're starting a new group chat with users
86
+ // specified in the array.
87
+ // 2. User is sending a message to a specific user.
88
+ // 3. No additional form params and the message goes to an existing group chat.
89
+ if (utils.getType(threadID) === "Array") {
90
+ for (var i = 0; i < threadID.length; i++) form["specific_to_list[" + i + "]"] = "fbid:" + threadID[i];
91
+ form["specific_to_list[" + threadID.length + "]"] = "fbid:" + ctx.userID;
92
+ form["client_thread_id"] = "root:" + messageAndOTID;
93
+ log.info("sendMessage", "Sending message to multiple users: " + threadID);
94
+ } else {
95
+ // This means that threadID is the id of a user, and the chat
96
+ // is a single person chat
97
+ if (isSingleUser) {
98
+ form["specific_to_list[0]"] = "fbid:" + threadID;
99
+ form["specific_to_list[1]"] = "fbid:" + ctx.userID;
100
+ form["other_user_fbid"] = threadID;
101
+ } else form["thread_fbid"] = threadID;
102
+ }
103
+
104
+ if (ctx.globalOptions.pageID) {
105
+ form["author"] = "fbid:" + ctx.globalOptions.pageID;
106
+ form["specific_to_list[1]"] = "fbid:" + ctx.globalOptions.pageID;
107
+ form["creator_info[creatorID]"] = ctx.userID;
108
+ form["creator_info[creatorType]"] = "direct_admin";
109
+ form["creator_info[labelType]"] = "sent_message";
110
+ form["creator_info[pageID]"] = ctx.globalOptions.pageID;
111
+ form["request_user_id"] = ctx.globalOptions.pageID;
112
+ form["creator_info[profileURI]"] = "https://www.facebook.com/profile.php?id=" + ctx.userID;
113
+ }
114
+
115
+ defaultFuncs
116
+ .post("https://www.facebook.com/messaging/send/", ctx.jar, form)
117
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
118
+ .then(function(resData) {
119
+ if (!resData) return callback({ error: "Send message failed." });
120
+ if (resData.error) {
121
+ if (resData.error === 1545012) log.warn("sendMessage", "Got error 1545012. This might mean that you're not part of the conversation " + threadID);
122
+ return callback(resData);
123
+ }
124
+
125
+ var messageInfo = resData.payload.actions.reduce(function(p, v) {
126
+ return ({
127
+ threadID: v.thread_fbid,
128
+ messageID: v.message_id,
129
+ timestamp: v.timestamp
130
+ } || p);
131
+ }, null);
132
+
133
+ return callback(null, messageInfo);
134
+ })
135
+ .catch(function(err) {
136
+ log.error("sendMessage", err);
137
+ if (utils.getType(err) == "Object" && err.error === "Not logged in.") ctx.loggedIn = false;
138
+ return callback(err);
139
+ });
140
+ }
141
+
142
+ function send(form, threadID, messageAndOTID, callback, isGroup) {
143
+ // fix lỗi = cach fetch threadID
144
+ // iq 5 trieu nam =))
145
+ if (utils.getType(threadID) === "Array") sendContent(form, threadID, false, messageAndOTID, callback);
146
+ else {
147
+ var THREADFIX = "ThreadID".replace("ThreadID", threadID);
148
+ if (THREADFIX.length <= 15 && THREADFIX.indexOf(1) == 0) return sendContent(form, threadID, !isGroup, messageAndOTID, callback);
149
+ else if (THREADFIX.length >= 15) return sendContent(form, threadID, threadID.length === 15, messageAndOTID, callback);
150
+ else return sendContent(form, threadID, threadID.length === 15, messageAndOTID, callback);
151
+ }
152
+ }
153
+
154
+ function handleUrl(msg, form, callback, cb) {
155
+ if (msg.url) {
156
+ form["shareable_attachment[share_type]"] = "100";
157
+ getUrl(msg.url, function(err, params) {
158
+ if (err) return callback(err);
159
+ form["shareable_attachment[share_params]"] = params;
160
+ cb();
161
+ });
162
+ } else cb();
163
+ }
164
+
165
+ function handleLocation(msg, form, callback, cb) {
166
+ if (msg.location) {
167
+ if (msg.location.latitude == null || msg.location.longitude == null) return callback({ error: "location property needs both latitude and longitude" });
168
+ form["location_attachment[coordinates][latitude]"] = msg.location.latitude;
169
+ form["location_attachment[coordinates][longitude]"] = msg.location.longitude;
170
+ form["location_attachment[is_current_location]"] = !!msg.location.current;
171
+ }
172
+ cb();
173
+ }
174
+
175
+ function handleSticker(msg, form, callback, cb) {
176
+ if (msg.sticker) form["sticker_id"] = msg.sticker;
177
+ cb();
178
+ }
179
+
180
+ function handleEmoji(msg, form, callback, cb) {
181
+ if (msg.emojiSize != null && msg.emoji == null) return callback({ error: "emoji property is empty" });
182
+ if (msg.emoji) {
183
+ if (msg.emojiSize == null) msg.emojiSize = "medium";
184
+ if (msg.emojiSize != "small" && msg.emojiSize != "medium" && msg.emojiSize != "large") return callback({ error: "emojiSize property is invalid" });
185
+ if (form["body"] != null && form["body"] != "") return callback({ error: "body is not empty" });
186
+ form["body"] = msg.emoji;
187
+ form["tags[0]"] = "hot_emoji_size:" + msg.emojiSize;
188
+ }
189
+ cb();
190
+ }
191
+
192
+ function handleAttachment(msg, form, callback, cb) {
193
+ if (msg.attachment) {
194
+ form["image_ids"] = [];
195
+ form["gif_ids"] = [];
196
+ form["file_ids"] = [];
197
+ form["video_ids"] = [];
198
+ form["audio_ids"] = [];
199
+
200
+ if (utils.getType(msg.attachment) !== "Array") msg.attachment = [msg.attachment];
201
+
202
+ uploadAttachment(msg.attachment, function(err, files) {
203
+ if (err) return callback(err);
204
+ files.forEach(function(file) {
205
+ var key = Object.keys(file);
206
+ var type = key[0]; // image_id, file_id, etc
207
+ form["" + type + "s"].push(file[type]); // push the id
208
+ });
209
+ cb();
210
+ });
211
+ } else cb();
212
+ }
213
+
214
+ function handleMention(msg, form, callback, cb) {
215
+ if (msg.mentions) {
216
+ for (let i = 0; i < msg.mentions.length; i++) {
217
+ const mention = msg.mentions[i];
218
+ const tag = mention.tag;
219
+ if (typeof tag !== "string") return callback({ error: "Mention tags must be strings." });
220
+ const offset = msg.body.indexOf(tag, mention.fromIndex || 0);
221
+ if (offset < 0) log.warn("handleMention", 'Mention for "' + tag + '" not found in message string.');
222
+ if (mention.id == null) log.warn("handleMention", "Mention id should be non-null.");
223
+
224
+ const id = mention.id || 0;
225
+ const emptyChar = '\u200E';
226
+ form["body"] = emptyChar + msg.body;
227
+ form["profile_xmd[" + i + "][offset]"] = offset + 1;
228
+ form["profile_xmd[" + i + "][length]"] = tag.length;
229
+ form["profile_xmd[" + i + "][id]"] = id;
230
+ form["profile_xmd[" + i + "][type]"] = "p";
231
+ }
232
+ }
233
+ cb();
234
+ }
235
+
236
+ return function sendMessage(msg, threadID, callback, replyToMessage, isGroup) {
237
+ typeof isGroup == "undefined" ? isGroup = null : "";
238
+ if (!callback && (utils.getType(threadID) === "Function" || utils.getType(threadID) === "AsyncFunction")) return threadID({ error: "Pass a threadID as a second argument." });
239
+ if (!replyToMessage && utils.getType(callback) === "String") {
240
+ replyToMessage = callback;
241
+ callback = function() {};
242
+ }
243
+
244
+ var resolveFunc = function() {};
245
+ var rejectFunc = function() {};
246
+ var returnPromise = new Promise(function(resolve, reject) {
247
+ resolveFunc = resolve;
248
+ rejectFunc = reject;
249
+ });
250
+
251
+ if (!callback) {
252
+ callback = function(err, data) {
253
+ if (err) return rejectFunc(err);
254
+ resolveFunc(data);
255
+ };
256
+ }
257
+
258
+ var msgType = utils.getType(msg);
259
+ var threadIDType = utils.getType(threadID);
260
+ var messageIDType = utils.getType(replyToMessage);
261
+
262
+ if (msgType !== "String" && msgType !== "Object") return callback({ error: "Message should be of type string or object and not " + msgType + "." });
263
+
264
+ // Changing this to accomodate an array of users
265
+ if (threadIDType !== "Array" && threadIDType !== "Number" && threadIDType !== "String") return callback({ error: "ThreadID should be of type number, string, or array and not " + threadIDType + "." });
266
+
267
+ if (replyToMessage && messageIDType !== 'String') return callback({ error: "MessageID should be of type string and not " + threadIDType + "." });
268
+
269
+ if (msgType === "String") msg = { body: msg };
270
+ var disallowedProperties = Object.keys(msg).filter(prop => !allowedProperties[prop]);
271
+ if (disallowedProperties.length > 0) return callback({ error: "Dissallowed props: `" + disallowedProperties.join(", ") + "`" });
272
+
273
+ var messageAndOTID = utils.generateOfflineThreadingID();
274
+
275
+ var form = {
276
+ client: "mercury",
277
+ action_type: "ma-type:user-generated-message",
278
+ author: "fbid:" + ctx.userID,
279
+ timestamp: Date.now(),
280
+ timestamp_absolute: "Today",
281
+ timestamp_relative: utils.generateTimestampRelative(),
282
+ timestamp_time_passed: "0",
283
+ is_unread: false,
284
+ is_cleared: false,
285
+ is_forward: false,
286
+ is_filtered_content: false,
287
+ is_filtered_content_bh: false,
288
+ is_filtered_content_account: false,
289
+ is_filtered_content_quasar: false,
290
+ is_filtered_content_invalid_app: false,
291
+ is_spoof_warning: false,
292
+ source: "source:chat:web",
293
+ "source_tags[0]": "source:chat",
294
+ body: msg.body ? msg.body.toString() : "",
295
+ html_body: false,
296
+ ui_push_phase: "V3",
297
+ status: "0",
298
+ offline_threading_id: messageAndOTID,
299
+ message_id: messageAndOTID,
300
+ threading_id: utils.generateThreadingID(ctx.clientID),
301
+ "ephemeral_ttl_mode:": "0",
302
+ manual_retry_cnt: "0",
303
+ has_attachment: !!(msg.attachment || msg.url || msg.sticker),
304
+ signatureID: utils.getSignatureID(),
305
+ replied_to_message_id: replyToMessage
306
+ };
307
+
308
+ handleLocation(msg, form, callback, () =>
309
+ handleSticker(msg, form, callback, () =>
310
+ handleAttachment(msg, form, callback, () =>
311
+ handleUrl(msg, form, callback, () =>
312
+ handleEmoji(msg, form, callback, () =>
313
+ handleMention(msg, form, callback, () =>
314
+ send(form, threadID, messageAndOTID, callback, isGroup)
315
+ )
316
+ )
317
+ )
318
+ )
319
+ )
320
+ );
321
+
322
+ return returnPromise;
323
+ };
324
+ };