alicezetion 1.7.6 → 1.7.8

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