Browse code

added appinfo/info.xml appinfo/signature.json appinfo/routes.php CHANGELOG.txt README.md css/style.css js/settings.js js/sendsms.js js/adminsettings.js js/showsmstables.js templates/settings/admin.php templates/settings/personal.php templates/navigation/index.php lib/Controller/SmsrelentlessController.php lib/Service/SmsrelentlessService.php l10n/en_GB.js l10n/en_GB.json l10n/en_US.js l10n/en_US.json lib/Migration/Version133Date20240215094712.php

DoubleBastionAdmin authored on 14/02/2024 22:47:20
Showing 20 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,161 @@
1
+======= CHANGELOG =======
2
+
3
+Versions:
4
+
5
+== 1.0.0 - 2022-1-27 ==
6
+* Initial release.
7
+
8
+== 1.0.1 - 2022-3-31 ==
9
+* Changed presentation text.
10
+
11
+== 1.0.2 - 2022-4-13 ==
12
+* Changed application controller class, to respect custom path of 'datadirectory'.
13
+* Fixed filters row arrow not showing up when using Apache.
14
+* Added the 'Contributors.txt' file.
15
+
16
+== 1.0.3 - 2022-4-15 ==
17
+* Changed the way the app gets the timezone.
18
+
19
+== 1.0.4 - 2022-5-7 ==
20
+* Changed the data type of the 'message' column in the 'sms_relent_sent' and 'sms_relent_received' tables.
21
+
22
+== 1.0.5 - 2022-5-9 ==
23
+* Changed string length for 'message' column in 'sms_relent_sent' and 'sms_relent_received' tables.
24
+* Changed syntax of SQL queries and of encryption function.
25
+* Changed structure of webhook URLs in case Nextcloud is served on a subdirectory.
26
+
27
+== 1.0.6 - 2022-8-13 ==
28
+* Added support for Twilio.
29
+* Added support for new lines in messages and email notifications.
30
+* Solved column width issue in sent/received SMS tables.
31
+* Minor explanatory text changes.
32
+
33
+== 1.0.7 - 2022-8-16 ==
34
+* Solved bug related to receiving messages on Twilio number when it's not associated with any Messaging Service.
35
+* Changed css properties for Network column.
36
+
37
+== 1.0.8 - 2022-8-23 ==
38
+* Added support for Flowroute.
39
+* Added automatic scrolling to bottom of received/sent messages table when clicking on 'Received/Sent SMS Messages' button.
40
+* Added scroll bar to info pop-up notes.
41
+
42
+== 1.0.9 - 2022-9-3 ==
43
+* Added support for MMS.
44
+* Minor CSS improvements.
45
+* Small changes to explanatory text.
46
+
47
+== 1.1.0 - 2022-9-5 ==
48
+* Solved issue with previewing images picked from Nextcloud.
49
+* Text changes to README.md.
50
+
51
+== 1.1.1 - 2022-9-9 ==
52
+* Changed signature verification process for Twilio.
53
+* Removed Alphanumeric Sender ID for Flowroute, since it's not supported.
54
+* Minor text changes on presentation page and settings page.
55
+
56
+== 1.1.2 - 2022-10-27 ==
57
+* Changed CSS settings to match the modifications introduced in Nextcloud 25.
58
+
59
+== 1.1.3 - 2022-12-1 ==
60
+* Fixed SQL error that appeared in fresh installations.
61
+* Added support for dark themes.
62
+* Updated explanatory text for Telnyx on the Settings page.
63
+
64
+== 1.1.4 - 2022-12-2 ==
65
+* Changed migration files to prevent installation errors.
66
+* Modified 3 svg files converting text objects to paths.
67
+
68
+== 1.1.5 - 2023-2-28 ==
69
+* Fixed issue related to Twilio message signing.
70
+* Updated message pricing information in app description.
71
+
72
+== 1.1.6 - 2023-5-8 ==
73
+* Implemented showing display names of message authors before their messages.
74
+* Added checkbox to enable/disable prepending display names before messages.
75
+* Custom display names can be now saved for external phone numbers.
76
+* Restrictions for groups or users can be placed on phone numbers by admins.
77
+* Admins can see just their own messages or all the messages in their message tables.
78
+* Auto-replies with 'daily mode' and 'vacation mode' can be configured for any controlled phone number.
79
+* Added a new message table that lists all the messages grouped by phone numbers.
80
+* Added the ability to see all the messages sent/received to/from a phone number, by clicking on 
81
+  a button located below the number, in the 'Received SMS Messages' and 'Sent SMS Messages' tables
82
+
83
+== 1.1.7 - 2023-5-9 ==
84
+* Fixed bug related to not being able to see messages in pop-up windows and on grouped messages table.
85
+
86
+== 1.1.8 - 2023-5-9 ==
87
+* Fixed migration issue bug.
88
+
89
+== 1.1.9 - 2023-5-9 ==
90
+* Made the app available to upgrade to for Nextcloud 26.
91
+
92
+== 1.2.0 - 2023-5-20 ==
93
+* Fixed auto-reply bug.
94
+* Moved the API keys and alphanumeric sender ID fields from the Personal settings page to the Admin 
95
+  settings page.
96
+* Available phone numbers are loaded automatically when the app's icon is clicked.
97
+* When only one phone number is available, it is selected automatically in the 'Set ID' field.
98
+* Admins can share their API keys with other non-admins.
99
+* Admins can see only their messages and the messages of the non-admins whith whom they share their API 
100
+  keys. Non-admins can see only their messages.
101
+* Added pop-up window that shows the messages exchanged between 2 phone numbers and allows sending replies.
102
+
103
+== 1.2.1 - 2023-5-23 ==
104
+* Allowed non-admin users to see incoming messages received on the phone numbers they are restricted to.
105
+* Customized confirm pop-up windows.
106
+
107
+== 1.2.2 - 2023-5-24 ==
108
+* Changed how non-admins view sent messages.
109
+
110
+== 1.2.3 - 2023-5-24 ==
111
+* Fixed 'Load more messages' bug.
112
+* Changed the way the display name is searched for and added to old messages, during app upgrade.
113
+
114
+== 1.2.4 - 2023-5-30 ==
115
+* Fixed MMS files domain problem.
116
+* Made MMS URLs clickable.
117
+* Added refresh button for messages in pop-up windows.
118
+
119
+== 1.2.5 - 2023-6-3 ==
120
+* Fixed incoming MMS issue.
121
+* Added checkbox on Settings page to allow users to include their display names in the text
122
+  of the message itself.
123
+
124
+== 1.2.6 - 2023-6-22 ==
125
+* Fixed messages display issue for non-admins.
126
+* Fixed how non-admins are able to see the messages sent/received from/to the numbers that are
127
+  shared with them but not restricted to them.
128
+
129
+== 1.2.7 - 2023-7-15 ==
130
+* Fixed alert messages issue.
131
+* Fixed text color for dark themes.
132
+* Added 'full-day' exception to auto-reply.
133
+* Added auto-refresh button on received/sent messages pages.
134
+
135
+== 1.2.8 - 2023-10-30 ==
136
+* Changed main screenshot and modified presentation text.
137
+* Changed text on Settings page.
138
+* Marked the app as compatible with Nextcloud 27.
139
+
140
+== 1.2.9 - 2023-11-1 ==
141
+* Changed how the app sends notifications for incoming messages.
142
+
143
+== 1.3.0 - 2023-11-3 ==
144
+* Changed notifications mechanism so that non-admin users receive notifications 
145
+  for messages received on phone numbers shared with them.
146
+* Fixed bug related to listing received messages for non-admin users.
147
+* Minor text modifications on the settings pages.
148
+
149
+== 1.3.1 - 2023-11-6 ==
150
+* Simplified some complex prepared SQL queries.
151
+
152
+== 1.3.2 - 2023-12-18 ==
153
+* Replaced default fonts with 2 free and open source fonts ('Open Sans' and 'Inter'),
154
+  included in the 'fonts' directory.
155
+* Fixed minor CSS issues.
156
+
157
+== 1.3.3 - 2024-2-15 ==
158
+* Implemented auto-refresh of the received messages table, when new messages arrive.
159
+* Fixed bug related to listing received messages, for non-admins.
160
+* Removed the 'Start auto refresh' button on pop-up windows.
161
+* Made the app completely functional when installed in a custom 'apps' directory.
0 162
new file mode 100644
... ...
@@ -0,0 +1,159 @@
1
+<span style="display:block;height:15px!important"></span>
2
+<p align="center"><img src="https://git.doublebastion.com/sms-relentless/raw/develop/img/sms_relentless_logo.png" alt="SMS Relentless" width="191px" height="157px"/></p>
3
+
4
+<span style="display:block;height:20px!important"></span>
5
+
6
+**SMS Relentless is a Nextcloud application that allows sending and receiving SMS and MMS messages in Nextcloud.**
7
+
8
+A telnyx.com, plivo.com, twilio.com or flowroute.com account and a real phone number acquired from one of the 4 providers are needed.
9
+
10
+<span style="display:block;height:20px!important"></span>
11
+
12
+## Features
13
+
14
+<span style="display:block;height:10px!important"></span>
15
+
16
+* 🚀 Use one or multiple local phone numbers in countries of your choice, to send and receive SMS/MMS messages with your browser, on any device connected to the Internet.
17
+
18
+* 📑 Sent and received SMS/MMS messages are stored in the database per sending/receiving user and can be viewed in paginated tables with filters for every column.
19
+
20
+* 🖼️ Up to 10 files of various formats, including jpeg, png and gif, can be sent as MMS messages from MMS enabled phone numbers. Files included in incoming MMS messages are not downloaded automatically. They are stored as URL links to the actual files, so that the receivers can download them only if they trust the senders.
21
+
22
+* 📔 SMS/MMS messages older than a specified number of days can be deleted in bulk with one click and they are automatically archived in csv files stored in Nextcloud, before being removed from the database. This makes them available for future analysis.
23
+
24
+* 💻 Sending SMS/MMS messages to thousands of recipients can be achieved by uploading a txt/csv file containing the recipients' phone numbers and the same SMS/MMS is sent automatically to all. The time interval between two consecutive messages is configurable.
25
+
26
+* 👤 The Display Name of Nextcloud users can be prepended to their messages, to make the origin of messages clearer.
27
+
28
+* ⚠️ Admins can restrict the use of specific phone numbers to specific groups or users.
29
+
30
+* ✉️ Auto-replies in 'daily mode' and 'vacation mode' can be configured for any controlled phone number.
31
+
32
+* 🔏 SMS/MMS messages coming from Telnyx, Plivo and Twilio are checked for authenticity by verifying the SMS provider's signature.
33
+
34
+* 📧 Users receive notifications in Nextcloud and (optionally) emails when new SMS/MMS messages arrive.
35
+
36
+* 📄 Each sent message receives a delivery receipt displayed in the Sent SMS Messages table.
37
+
38
+* 📱 It works with regular 'long code' (10-digit) phone numbers, but also with 'toll-free' numbers and 'short codes'. Users see a list with their current phone numbers and can set them as Sender IDs. Setting alphanumeric Sender IDs is also possible. 
39
+
40
+* 💵 It allows checking the current Telnyx/Plivo/Twilio balance by selecting the provider on the left panel.
41
+
42
+* 💰 The only ongoing cost is about $1 per month (depending on the country) for an SMS/MMS enabled phone number located in a country chosen by the user. No contracts.
43
+
44
+* 💸 Low prices per SMS: starting from $0.0040 per sent message and $0.0040 per received message (Telnyx), or $0.0085 per sent message and $0.0085 per received message (Plivo), or $0.0109 per sent message and 0.0079 per received message (Twilio), or $0.0055 per sent message and 0.0040 per received message (Flowroute) in the USA.
45
+
46
+<span style="display:block;height:10px!important"></span>
47
+
48
+Double Bastion is not affiliated with Telnyx, Plivo, Twilio or Flowroute.
49
+
50
+### Donations
51
+
52
+* 🎁 [Donate](https://www.doublebastion.com/donations/)
53
+
54
+<span style="display:block;height:20px!important"></span>
55
+
56
+Send SMS message
57
+<span style="display:block;height:10px!important"></span>
58
+![Image of SMS Relentless Interface](https://git.doublebastion.com/sms-relentless/raw/develop/img/sms_relentless_send_sms.png)
59
+<span style="display:block;height:40px!important"></span>
60
+Send MMS message
61
+<span style="display:block;height:10px!important"></span>
62
+![Image of SMS Relentless Interface](https://git.doublebastion.com/sms-relentless/raw/develop/img/sms_relentless_send_mms.png)
63
+<span style="display:block;height:40px!important"></span>
64
+List received SMS messages
65
+<span style="display:block;height:10px!important"></span>
66
+![Image of SMS Relentless Interface](https://git.doublebastion.com/sms-relentless/raw/develop/img/sms_relentless_received_messages.png)
67
+<span style="display:block;height:40px!important"></span>
68
+List sent SMS messages
69
+<span style="display:block;height:10px!important"></span>
70
+![Image of SMS Relentless Interface](https://git.doublebastion.com/sms-relentless/raw/develop/img/sms_relentless_sent_messages.png)
71
+<span style="display:block;height:40px!important"></span>
72
+List messages grouped by phone number
73
+<span style="display:block;height:10px!important"></span>
74
+![Image of SMS Relentless Interface](https://git.doublebastion.com/sms-relentless/raw/develop/img/sms_relentless_grouped_by_number.png)
75
+<span style="display:block;height:40px!important"></span>
76
+List all messages exchanged between the sending and the receiving phone number
77
+<span style="display:block;height:10px!important"></span>
78
+![Image of SMS Relentless Interface](https://git.doublebastion.com/sms-relentless/raw/develop/img/sms_relentless_exchanged_messages_popup.png)
79
+<span style="display:block;height:40px!important"></span>
80
+List all messages sent from or received by phone number
81
+<span style="display:block;height:10px!important"></span>
82
+![Image of SMS Relentless Interface](https://git.doublebastion.com/sms-relentless/raw/develop/img/sms_relentless_messages_to_from_popup.png)
83
+<span style="display:block;height:40px!important"></span>
84
+Send SMS message to multiple recipients
85
+<span style="display:block;height:10px!important"></span>
86
+![Image of SMS Relentless Interface](https://git.doublebastion.com/sms-relentless/raw/develop/img/sms_relentless_send_mass_sms.png)
87
+<span style="display:block;height:40px!important"></span>
88
+Filter messages by date and keyword
89
+<span style="display:block;height:10px!important"></span>
90
+![Image of SMS Relentless Interface](https://git.doublebastion.com/sms-relentless/raw/develop/img/sms_relentless_filter_messages_by_date_and_keyword.png)
91
+<span style="display:block;height:40px!important"></span>
92
+Delete old SMS messages
93
+<span style="display:block;height:10px!important"></span>
94
+![Image of SMS Relentless Interface](https://git.doublebastion.com/sms-relentless/raw/develop/img/sms_relentless_delete_old_messages.png)
95
+<span style="display:block;height:40px!important"></span>
96
+
97
+## Browsers
98
+<span style="display:block;height:10px!important"></span>
99
+
100
+SMS Relentless works with all major browsers.
101
+
102
+<span style="display:block;height:20px!important"></span>
103
+
104
+## Programming Languages
105
+<span style="display:block;height:10px!important"></span>
106
+
107
+SMS Relentless only uses PHP, SQL, jQuery, CSS and HTML. This means it's efficient, light-weight and easy to maintain and debug.
108
+
109
+<span style="display:block;height:20px!important"></span>
110
+
111
+## Minimum Requirements
112
+<span style="display:block;height:10px!important"></span>
113
+
114
+- **Nextcloud 22+** has to be installed and properly configured, preferably by following the <a href="https://www.doublebastion.com/install-nextcloud/" rel="noreferrer noopener" target="_blank">Install Nextcloud</a> chapter in our guide.
115
+
116
+- **A telnyx.com, plivo.com, twilio.com or flowroute.com account and an SMS/MMS enabled phone number** attached to it.
117
+
118
+- The **libcurl** PHP library has to be installed on the server (it's usually installed automatically when PHP is installed).
119
+
120
+To enable email notifications for every received SMS/MMS, the "sendmail" utility ("/usr/sbin/sendmail" on Debian Linux), has to be present on the server. "sendmail" is a binary which gets 
121
+installed when Postfix is installed. Also, the web server user (www-data) has to be allowed to send emails from command line (by specifying "authorized\_submit\_users = www-data" in 
122
+"/etc/postfix/main.cf" for Postfix on Debian).
123
+
124
+<span style="display:block;height:20px!important"></span>
125
+
126
+## Installation
127
+<span style="display:block;height:10px!important"></span>
128
+
129
+<a href="https://www.doublebastion.com/install-nextcloud/#install-sms-relentless" rel="noreferrer noopener" target="_blank">This chapter</a> of our Complete Guide to a Complete Linux Server 
130
+explains in detail how to install and use this application.
131
+
132
+SMS Relentless is a component of RED Scarf Suite. It can be installed and used alone, but if you want to install <a href="https://www.doublebastion.com/red-scarf-suite-components/" rel="noreferrer noopener" target="_blank">all 
133
+the components</a> of RED Scarf Suite, you can follow our <a href="https://www.doublebastion.com/free-server/complete-guide-to-a-complete-linux-server/" rel="noreferrer noopener" target="_blank">complete guide</a>.
134
+
135
+<span style="display:block;height:20px!important"></span>
136
+
137
+## Contribute
138
+<span style="display:block;height:10px!important"></span>
139
+
140
+This is the official git repository of SMS Relentless. The <a href="https://github.com/DoubleBastionAdmin/sms-relentless" rel="noreferrer noopener" target="_blank">GitHub SMS Relentless
141
+repository</a> is just a pointer to this repository. We don’t use GitHub for developing SMS Relentless because GitHub is owned by one of the companies that proved their disrespect for
142
+digital freedom over the years and because centralized services create autonomy and privacy issues, in spite of all the benefits.
143
+
144
+If you want to contribute code to this project, please submit <a href="https://git.doublebastion.com/sms-relentless/pullrequests/contrib" rel="noreferrer noopener" target="_blank">this form</a>, 
145
+mentioning your intended changes. We'll send you the credentials needed to push code to the "contrib" branch of this repository. After we review the changes we can include them in the 
146
+project.
147
+
148
+Please post any bugs that are not security related, or feature requests, on the <a href="https://git.doublebastion.com/sms-relentless/issues/develop" rel="noreferrer noopener" target="_blank">
149
+issue tracker</a>. If you notice bugs related to security, don’t post them on the issue tracker; instead, send them to manager [at] doublebastion [dot] com .
150
+
151
+<span style="display:block;height:20px!important"></span>
152
+
153
+## License
154
+<span style="display:block;height:10px!important"></span>
155
+
156
+SMS Relentless as a whole is licensed under the GNU Affero General Public License Version 3, or any later version. If you use SMS Relentless or distribute it in modified or unmodified 
157
+form, you will need to comply with the terms of the GNU Affero General Public License Version 3, or any later version.
158
+
159
+SMS Relentless includes libraries licensed under different free software licenses. These libraries contain their respective original copyright notices.
0 160
new file mode 100644
... ...
@@ -0,0 +1,93 @@
1
+<?xml version="1.0"?>
2
+<info xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
3
+      xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
4
+    <id>sms_relentless</id>
5
+    <name>SMS Relentless</name>
6
+    <summary>Send and receive SMS in Nextcloud</summary>
7
+    <description><![CDATA[
8
+This application allows sending and receiving SMS and MMS messages in Nextcloud. An SMS/MMS enabled phone number acquired from 
9
+Telnyx, Plivo, Twilio or Flowroute is needed. Detailed instructions on how to configure and use this application can be found on the 'Admin documentation' page.
10
+
11
+### Features:
12
+
13
+* 🚀 Use one or multiple local phone numbers in countries of your choice, to send and receive SMS/MMS messages with your browser, on any device connected to the Internet.
14
+
15
+* 📑 Sent and received SMS/MMS messages are stored in the database per sending/receiving user and can be viewed in paginated tables with filters for every column.
16
+
17
+* 🖼️  Up to 10 files of various formats, including jpeg, png and gif, can be sent as MMS messages from MMS enabled phone numbers. Files included in incoming MMS messages are not downloaded automatically. They are stored as URL links to the actual files, so that the receivers can download them only if they trust the senders.
18
+
19
+* 📔 SMS/MMS messages older than a specified number of days can be deleted in bulk with one click and they are automatically archived in csv files stored in Nextcloud, before being removed from the database. This makes them available for future analysis.
20
+
21
+* 💻 Sending SMS/MMS messages to thousands of recipients can be achieved by uploading a txt/csv file containing the recipients' phone numbers and the same SMS/MMS is sent automatically to all. The time interval between two consecutive messages is configurable.
22
+
23
+* 👤 The Display Name of Nextcloud users can be prepended to their messages, to make the origin of messages clearer.
24
+
25
+* ⚠️  Admins can restrict the use of specific phone numbers to specific groups or users.
26
+
27
+* ✉️  Auto-replies in 'daily mode' and 'vacation mode' can be configured for any controlled phone number.
28
+
29
+* 🔏 SMS/MMS messages coming from Telnyx, Plivo and Twilio are checked for authenticity by verifying the SMS provider's signature.
30
+
31
+* 📧 Users receive notifications in Nextcloud and (optionally) emails when new SMS/MMS messages arrive.
32
+
33
+* 📄 Each sent message receives a delivery receipt displayed in the Sent SMS Messages table.
34
+
35
+* 📱 It works with regular 'long code' (10-digit) phone numbers, but also with 'toll-free' numbers and 'short codes'. Users see a list with their current phone numbers and can set them as Sender IDs. Setting alphanumeric Sender IDs is also possible. 
36
+
37
+* 💵 It allows checking the current Telnyx/Plivo/Twilio balance by selecting the provider on the left panel.
38
+
39
+* 💰 The only ongoing cost is about $1 per month (depending on the country) for an SMS/MMS enabled phone number located in a country chosen by the user. No contracts.
40
+
41
+* 💸 Low prices per SMS: starting from $0.0040 per sent message and $0.0040 per received message (Telnyx), or $0.0085 per sent message and $0.0085 per received message (Plivo), or $0.0109 per sent message and 0.0079 per received message (Twilio), or $0.0055 per sent message and 0.0040 per received message (Flowroute) in the USA.
42
+
43
+We have no affiliation with Telnyx, Plivo, Twilio or Flowroute.
44
+
45
+### Documentation
46
+
47
+* [Admin documentation](https://www.doublebastion.com/install-nextcloud/#install-sms-relentless)
48
+
49
+### Donations
50
+
51
+* 🎁 [Donate](https://www.doublebastion.com/donations/)
52
+
53
+    ]]></description>
54
+    <version>1.3.3</version>
55
+    <licence>AGPL</licence>
56
+    <author mail="contact@doublebastion.com">Double Bastion LLC</author>
57
+    <namespace>SMSRelentless</namespace>
58
+	<documentation>
59
+		<admin>https://www.doublebastion.com/install-nextcloud/#install-sms-relentless</admin>
60
+	</documentation>
61
+    <category>office</category>
62
+    <category>organization</category>
63
+
64
+    <website>https://www.doublebastion.com/sms-relentless/</website>
65
+    <bugs>https://git.doublebastion.com/sms-relentless/issues/develop</bugs>
66
+    <repository>https://git.doublebastion.com/sms-relentless/develop/</repository>
67
+
68
+    <screenshot>https://git.doublebastion.com/sms-relentless/raw/develop/img/sms_relentless_sent_messages.png</screenshot>
69
+    <screenshot>https://git.doublebastion.com/sms-relentless/raw/develop/img/sms_relentless_received_messages.png</screenshot>
70
+    <screenshot>https://git.doublebastion.com/sms-relentless/raw/develop/img/sms_relentless_grouped_by_number.png</screenshot>
71
+    <screenshot>https://git.doublebastion.com/sms-relentless/raw/develop/img/sms_relentless_exchanged_messages_popup.png</screenshot>
72
+    <screenshot>https://git.doublebastion.com/sms-relentless/raw/develop/img/sms_relentless_send_mms.png</screenshot>
73
+
74
+    <dependencies>
75
+            <nextcloud min-version="26" max-version="28" />
76
+    </dependencies>
77
+
78
+    <navigations>
79
+        <navigation>
80
+            <name>SMS Relentless</name>
81
+            <route>sms_relentless.page.index</route>
82
+            <order>102</order>
83
+            <icon>sms_relentless.svg</icon>
84
+        </navigation>
85
+    </navigations>
86
+
87
+    <settings>
88
+            <personal>OCA\SMSRelentless\Settings\Personal</personal>
89
+            <personal-section>OCA\SMSRelentless\Settings\PersonalSection</personal-section>
90
+            <admin>OCA\SMSRelentless\Settings\Admin</admin>
91
+    	    <admin-section>OCA\SMSRelentless\Settings\AdminSection</admin-section>
92
+    </settings>
93
+</info>
0 94
new file mode 100644
... ...
@@ -0,0 +1,83 @@
1
+<?php
2
+/**
3
+ * @copyright 2021 Double Bastion LLC <www.doublebastion.com>
4
+ *
5
+ * @author Double Bastion LLC
6
+ *
7
+ * @license GNU AGPL version 3 or any later version
8
+ *
9
+ * This program is free software; you can redistribute it and/or
10
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
11
+ * License as published by the Free Software Foundation; either
12
+ * version 3 of the License, or any later version.
13
+ *
14
+ * This program is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
18
+ *
19
+ * You should have received a copy of the GNU Affero General Public
20
+ * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
+ *
22
+ */
23
+
24
+declare(strict_types=1);
25
+
26
+return [
27
+  'routes' => [
28
+     // User views
29
+     ['name' => 'page#index', 'url' => '/', 'verb' => 'GET'],
30
+     ['name' => 'author_api#receivesmstel', 'url' => '/api/recsmstel', 'verb' => 'POST'],
31
+     ['name' => 'author_api#receivesmsnex', 'url' => '/api/recsmsnex', 'verb' => 'POST'],
32
+     ['name' => 'author_api#receivesmstwil', 'url' => '/api/recsmstwil', 'verb' => 'POST'],
33
+     ['name' => 'author_api#receivesmsflow', 'url' => '/api/recsmsflow', 'verb' => 'POST'],
34
+     ['name' => 'author_api#recdeliveryreptel', 'url' => '/api/recdeliverytel', 'verb' => 'POST'],
35
+     ['name' => 'author_api#recdeliveryrepnex', 'url' => '/api/recdeliverynex', 'verb' => 'POST'],
36
+     ['name' => 'author_api#recdeliveryreptwil', 'url' => '/api/recdeliverytwil', 'verb' => 'POST'],
37
+     ['name' => 'author_api#recdeliveryrepflow', 'url' => '/api/recdeliveryflow', 'verb' => 'POST'],
38
+     ['name' => 'smsrelentless#cleantempdir', 'url' => '/user/cleantempdir/{userId}', 'verb' => 'POST'],
39
+     ['name' => 'smsrelentless#cleanmultrecdir', 'url' => '/user/cleanmultrecdir/{userId}', 'verb' => 'POST'],
40
+     ['name' => 'smsrelentless#getreceivedtable', 'url' => '/user/getreceivedtable/{userId}', 'verb' => 'GET'],
41
+     ['name' => 'smsrelentless#getreceivedtablefordel', 'url' => '/user/getreceivedtablefordel/{userId}', 'verb' => 'GET'],
42
+     ['name' => 'smsrelentless#getsenttable', 'url' => '/user/getsenttable/{userId}', 'verb' => 'GET'],
43
+     ['name' => 'smsrelentless#getsenttablefordel', 'url' => '/user/getsenttablefordel/{userId}', 'verb' => 'GET'],
44
+     ['name' => 'smsrelentless#getgroupedtable', 'url' => '/user/getgroupedtable/{userId}', 'verb' => 'GET'],
45
+     ['name' => 'smsrelentless#getgroupedpernumber', 'url' => '/user/getgroupedpernumber/{userId}', 'verb' => 'POST'],
46
+     ['name' => 'smsrelentless#getgroupedforreply', 'url' => '/user/getgroupedforreply/{userId}', 'verb' => 'POST'],
47
+     ['name' => 'smsrelentless#removerecrows', 'url' => '/user/removerecrows/{userId}', 'verb' => 'POST'],
48
+     ['name' => 'smsrelentless#removesentrows', 'url' => '/user/removesentrows/{userId}', 'verb' => 'POST'],
49
+     ['name' => 'smsrelentless#saveoldrecrows', 'url' => '/user/saveoldrecrows/{userId}', 'verb' => 'POST'],
50
+     ['name' => 'smsrelentless#saveoldsentrows', 'url' => '/user/saveoldsentrows/{userId}', 'verb' => 'POST'],
51
+     ['name' => 'smsrelentless#getappdirectory', 'url' => '/user/getappdirectory/{userId}', 'verb' => 'GET'],
52
+     ['name' => 'smsrelentless#getbalancetel', 'url' => '/user/getbalancetel/{userId}', 'verb' => 'POST'],
53
+     ['name' => 'smsrelentless#getbalancenex', 'url' => '/user/getbalancenex/{userId}', 'verb' => 'POST'],
54
+     ['name' => 'smsrelentless#getbalancetwil', 'url' => '/user/getbalancetwil/{userId}', 'verb' => 'POST'],
55
+     ['name' => 'smsrelentless#getbalanceflow', 'url' => '/user/getbalanceflow/{userId}', 'verb' => 'POST'],
56
+     ['name' => 'smsrelentless#getsmsnumbers', 'url' => '/user/getsmsnumbers/{userId}', 'verb' => 'POST'],
57
+     ['name' => 'smsrelentless#refreshavailablenumbers', 'url' => '/user/refreshavailablenumbers/{userId}', 'verb' => 'POST'],
58
+     ['name' => 'smsrelentless#upload_numbers_file', 'url' => '/user/upload_numbers_file/{userId}', 'verb' => 'POST'],
59
+     ['name' => 'smsrelentless#uploadfile', 'url' => '/user/uploadfile/{userId}', 'verb' => 'POST'],
60
+     ['name' => 'smsrelentless#pickfile', 'url' => '/user/pickfile/{userId}', 'verb' => 'POST'],
61
+     ['name' => 'smsrelentless#removeupfile', 'url' => '/user/removeupfile/{userId}', 'verb' => 'POST'],
62
+     ['name' => 'smsrelentless#sendsmstel', 'url' => '/user/sendsmstel/{userId}', 'verb' => 'POST'],
63
+     ['name' => 'smsrelentless#sendsmsnex', 'url' => '/user/sendsmsnex/{userId}', 'verb' => 'POST'],
64
+     ['name' => 'smsrelentless#sendsmstwil', 'url' => '/user/sendsmstwil/{userId}', 'verb' => 'POST'],
65
+     ['name' => 'smsrelentless#sendsmsflow', 'url' => '/user/sendsmsflow/{userId}', 'verb' => 'POST'],
66
+     ['name' => 'smsrelentless#getmsgsperpagenewmsg', 'url' => '/user/getmsgsperpagenewmsg/{userId}', 'verb' => 'GET'],
67
+     ['name' => 'smsrelentless#getnewmsgindicator', 'url' => '/user/getnewmsgindicator/{userId}', 'verb' => 'GET'],
68
+     ['name' => 'smsrelentless#savedisplayname', 'url' => '/user/savedisplayname/{userId}', 'verb' => 'POST'],
69
+     ['name' => 'smsrelentless#getautoreplyconf', 'url' => '/user/getautoreplyconf/{userId}', 'verb' => 'GET'],
70
+     // Settings
71
+     ['name' => 'smsrelentless#getsettings', 'url' => '/user/getsettings/{userId}', 'verb' => 'GET'],
72
+     ['name' => 'smsrelentless#getadminsettings', 'url' => '/user/getadminsettings/{userId}', 'verb' => 'GET'],
73
+     ['name' => 'smsrelentless#updatesettings', 'url' => '/user/updatesettings/{userId}', 'verb' => 'PUT'],
74
+     ['name' => 'smsrelentless#updatepersadmnsettings', 'url' => '/user/updatepersadmnsettings/{userId}', 'verb' => 'PUT'],
75
+     ['name' => 'smsrelentless#updateadminsettings', 'url' => '/user/updateadminsettings/{userId}', 'verb' => 'PUT'],
76
+     ['name' => 'smsrelentless#updatenumberrestrictions', 'url' => '/user/updatenumberrestrictions/{userId}', 'verb' => 'PUT'],
77
+     ['name' => 'smsrelentless#updatekeysallowedusers', 'url' => '/user/updatekeysallowedusers/{userId}', 'verb' => 'PUT'],
78
+     ['name' => 'smsrelentless#updateautoreplies', 'url' => '/user/updateautoreplies/{userId}', 'verb' => 'PUT'],
79
+     ['name' => 'smsrelentless#removenumberrestrictions', 'url' => '/user/removenumberrestrictions/{userId}', 'verb' => 'POST'],
80
+     ['name' => 'smsrelentless#removeautoreplies', 'url' => '/user/removeautoreplies/{userId}', 'verb' => 'POST'],
81
+  ]
82
+];
83
+
0 84
new file mode 100644
... ...
@@ -0,0 +1,905 @@
1
+{
2
+    "hashes": {
3
+        "CHANGELOG.txt": "549b92657db2a34599b36b2cf6320614e53b55d2bff08eb32d35efaa874e189d8a57f5e682a556edb1f74d36ca87c7658ca230595431aed3f83ec0555a5b6fdd",
4
+        "COPYING.txt": "a0a86214ea153fb07ff35ceec0848dd1703eae22de036a825efc8394e50f65e3044832f3b49cf7e45a39edc470bdf738abc36a3a78ca7df3a6e73c14eaef94a8",
5
+        "Contributors.txt": "8ab4ea9b8c38e4d115af6ca08e8e27592198b763982bd166b67f38ee0b9f2b7e093cd58ce0927ae38ee3bc015b129add2ffeb3967288c804da493241bc67ba9b",
6
+        "README.md": "94f40f47967f4b9c4f71a47a6a7b246843b82df52a122aea8f8c1c4d2330c4cb5666e5fb0f5e0c0ad718e91f0a06f28dcb5b58ed7dde77e2666ca7f0982578bf",
7
+        "appinfo\/info.xml": "0878962f93dd6632d07b9a47bee7f6ee7e1896a30068a80d55c3a9ccdb038dab9c2a2079c26f42a7284bf4b628f395dba7e102d1275656bbb4316255be550796",
8
+        "appinfo\/routes.php": "a8afb27a329e6da1fd08ff030b7be5fe3b6f59f5022875e4fa248d62ce951bb9017b63707cff35e539fb78cb80f7c83b29ec5089581be77fd3781a7cd912713b",
9
+        "css\/style.css": "4bb31a2356b69fe0274a133d15c3ce074e4c80ac12ee8d1cbb0d5c798bf76317fe6ba7832e39709dc086195e9658a17f680336f62eb15145ef250de97e76d00b",
10
+        "fonts\/Apache_License_v2.0_Open_Sans.txt": "fdae7ed259455ca9fa45939e7f25cbb4de29831cda16d9151de25a5f6e9d9be43b053f4fd3b896026239fca77abce04f543d591c501ecf4ce18c854bc0a51660",
11
+        "fonts\/Inter-Bold.woff": "f34ed611dc0ba6e7c0bf7242bad7c02e09f208bfbdd21d6649ebf9b41bc06696d8856707851944786c80c718df455e619caab170c70bfe97ba2043d651d4532e",
12
+        "fonts\/Inter-Bold.woff2": "736b4aaf8a2de0c17fbd5396a338577227326f078ee0646072d851d328b58a8058989af8735ac073f935b05f291d9310797d95c963e5e3ff0ea61a87f21c9da5",
13
+        "fonts\/Inter-BoldItalic.woff": "619e398d37249fae96ba0deb06fcf5dab215ba888740024287e2c8f1278b33273124cd5b9ea8f7525a17657566b72a1661b688ca670bc068ca6ddf466b7e7ffe",
14
+        "fonts\/Inter-BoldItalic.woff2": "a24bdb558a9b26fbe7631d6cf90b8db8f5f0164c3c814a2971fb7d45e807b0856454893bbd0d5bd0d9f060689f2be5f5bb1b69e4bdea0293d1122e13ad28e96f",
15
+        "fonts\/Inter-Italic.woff": "72defeb5040f6375683dba41d4ce43654fdbae4f64aea88b01feb023b3e894c278c8a8c7e5583b6d83d980495ca0d5afa5ec7e1bfcc731be08d3dbe1b8b3f348",
16
+        "fonts\/Inter-Italic.woff2": "b128da83c81fe4a28026dc0a2a75c7920f37d4e04d6d6bde4e60b3a9527dbff04ff0ebc8b300874db9bd90036a41a52f4c9d82eb2f78fb8e99a35bb04defa1c2",
17
+        "fonts\/Inter-Medium.woff": "1f7c25aeb1ed534a106254fdba6bf59dfa03542f813489dca31fe067e2a22ab9549babb48af4cd465ab3ef0ef2f4b0f46532efcc8aae8942ad2cf98d0a5a4a3f",
18
+        "fonts\/Inter-Medium.woff2": "ce94d1a0cea81d42546ebc0247403b02c6fae24d3afba618cf658436734557a8b2b8ebed54319a9f66b233bd224da3685f848470866de63a144c8c28070491d4",
19
+        "fonts\/Inter-MediumItalic.woff": "7b7bef9c7a7717c6d52d619059e5ec258b537f538ada38325c2c7bfa4968ff53109bc9ee17a57819ef37d0a145a973f4a7c8e4d8d09e71d3faa4d0fe14cbf487",
20
+        "fonts\/Inter-MediumItalic.woff2": "4a2c5dc8c2ece82489e63b16cd8b1536b8f5502cf8f93307b0c71c6d54594a28ec2a80b8e58dfbbcc1d38a51aa8dd6d6fa025aed2cdc1429a462745a2bf2d414",
21
+        "fonts\/Inter-Regular.woff": "e37409956d19653617af32af2f99f4038c815a3664f2dcb2fef5e6a1a7345c78aaac3badc2ae499b1423514076ad676ab4bd5d936ef9d159899a6f668d991e4c",
22
+        "fonts\/Inter-Regular.woff2": "731924aedf31d6ef8fcd57a3b74182331ec7ba743d64033d8912d350ba98fd5b1942decaa4268f4dc925be2ed711c71a77200b2497bec10cae499b452fb27138",
23
+        "fonts\/Inter-SemiBold.woff": "684602b1f45bf7a9ca5ea6b1aca2cc2046e07ac79eb63b920099463f25866f50cca77ca253f16078d3a6e781ca23b964a69c87389621fa101d5cfffdb292d132",
24
+        "fonts\/Inter-SemiBold.woff2": "12b7680eccc54f56f800ac3ea4eff0490f515911d0fc83f99f62fa0f72d848155c8a7186918301a372d0fd0238d8093109c7b9b3c05168058e3cb47b1f7216ae",
25
+        "fonts\/Inter-SemiBoldItalic.woff": "9623d9c91148b651b7d4a642751e4f9eaeda68b6f4c33355d0173e303252039b3bcd301556a1d8451ffbd36d7996c1e8fc5ca1276884636cf57468e38c9e442a",
26
+        "fonts\/Inter-SemiBoldItalic.woff2": "97b7d8ab268ebcbc00876bd69ca9cc7cf2ae9ba5a6a30c13e3412e41a88f1f5ed758a6d9abbab3a14359943a003b14307cbc379bb11505c014b002322fd53c6e",
27
+        "fonts\/SIL_Open_Font_License_v1.1_Inter.txt": "073e141d4e45a3adfd2cb569db6a4fd217b1721dd6aeab8159e36940b984df5ebdc345deb0eb6be65367f943e516a12dff41eb1238a322d248ca3478c50ef9b6",
28
+        "fonts\/opensans-bold.woff": "d094832745611e047ffa87fdb21bac41befabdb07aecade483d4dc5a5b97bad00f1d4a5dca2a615789cd494791f0ab4209be537eb4b1bc7cbee7c42eb5e201dc",
29
+        "fonts\/opensans-bold.woff2": "096abb618c9ce1a534f0198aeea53c6d1138000f98b883131ab49ee48b80b483af635f0196ac40a1c1bde679f63b3c3b907b8f9b0102a752862d623dd22393a5",
30
+        "fonts\/opensans-bolditalic.woff": "c80f105a10d37c812f5d1b29445cd21cbc95594f71d9c5fc1b3aeeb9985c5465ba017654f1453baefdc56cc27aa325b586d77323012073eb713ab8f88f08dab4",
31
+        "fonts\/opensans-bolditalic.woff2": "38b99ebf320264d74a456fe590fc610580b003bc77a39d97ff42dec41353a8f908d6f680b4777cdb34ed544d9b4ed20dce8c418317de1d721e25ab670f49fc1d",
32
+        "fonts\/opensans-extrabold.woff": "6636a395ba345853ada2237b8e1f81c52e54bfb65559cbcb8de143cac00232f20cf34c764c9c4d4b80e82dae79cba3064ebdf22999cce8839df2d5709ee64092",
33
+        "fonts\/opensans-extrabold.woff2": "758c90eb07c6db7e78cb703ea285f82b443ca2cfab792328a3f8c14acc1f932ae79ec2987b8b94bf19b3cc16fae31c76f3164c9437a2591283fb1592e40ec33d",
34
+        "fonts\/opensans-extrabolditalic.woff": "ab1966f1ab3bb436e489c2d6ee562cf22d05b6b8c9bbca17e903518311aa45659efc329255e08ab597e2b8effe3bda602a7fb56b7d0c1d872b69337537d49dff",
35
+        "fonts\/opensans-extrabolditalic.woff2": "2132d6309969f868521f2d788b991bc9bcf3239f1768db9a2b90faf8838c35efea85225b24db256f54c86d0a7915ecd50a7f5348e6ab040e0f172ba7510598cd",
36
+        "fonts\/opensans-italic.woff": "a9751e7ac7a3c3d9f739d1fe00730a545b68e4a6473beafee8edf583f175b34fd5e0b60a14ec3707c8691fdbebea17e191c51707f50a21281e76be46f55a1140",
37
+        "fonts\/opensans-italic.woff2": "7a80c01d34562e2fe248a71078ffa9413c04c9c320d27acb0bce96cc295101eb9e80a25e97dab3e67c184c40937862be820581441aa4100bd512a26ef2d523cf",
38
+        "fonts\/opensans-light.woff": "cca2c5d207e0935c1848e22965972cb6feea39aa93b1b546051cfabe5ab16e909934d007a7ccd174eda1e7671d838f477890dedcb93d68ba722eda39a16d0bb8",
39
+        "fonts\/opensans-light.woff2": "cdc332de1b13eb0f05cc9dd1ebc905fa5ce948eab71e2fdb1bc538ad54a0de980bf83352090becd650af9c101ec9a6898d2e4798e4fb777e41c20fae85fd568b",
40
+        "fonts\/opensans-lightitalic.woff": "26e7759869088d8abba380f0bb22bbb9fdf0a985c0999519390cbd85099e3f48864d866f4639a8ff1992e7c81c755b0bbf66f525d4d38a929067886e9b54eb88",
41
+        "fonts\/opensans-lightitalic.woff2": "b7f80b69abeca9d0369f5d46da192e98a6329cf1f948c897fb7130e0d815f73e293c37f0e6d0047273fe3f13a19e648d1bd06cfa2fac2142ec38ac244e7f0940",
42
+        "fonts\/opensans-regular.woff": "3a526ba177f8f16ad95941c185411f350fab7e5202b9f56ea9c5f972c62912781d66da10e278e065cc6748a4bc9ab9182d68b27eaf380131c602195148e4b8b4",
43
+        "fonts\/opensans-regular.woff2": "66b3e915b891f7b37b441ee18e40f01274fe19f2515470760e503f428fc1c524ccfbe832191978c2c5f6bc4b7ef46937e4f77f5457b6efbf878c97c054cb45f2",
44
+        "fonts\/opensans-semibold.woff": "173f703ab767d0fcff014dac2fa3dcac787ffd0eb39f0c532b6679935c0105daacfa6a32bca97de13e420e10194b701ad2487bfd35d28807563ebf0b16d0ca35",
45
+        "fonts\/opensans-semibold.woff2": "75068ba76befc2356fe83b198bf6da70e177e53cc3128af09d0d9f69dfe538013f2828b2363c6f533fcaca4d4b2a5ec5159b5eb6f288504ac73d33ac5d1d2c4d",
46
+        "fonts\/opensans-semibolditalic.woff": "9e1e965095991d4a12a0658fa22a116b043ce20fd5f73bb9655d870ae49c46170cec52827510be323332b535002eb96445f79c3d1e4dd0550ff622fda0465f1d",
47
+        "fonts\/opensans-semibolditalic.woff2": "d7e43f05802e26f4cb80ab6a492b01c398c5b41168c7f61356ca3ffc5f4fccabae5ba332956f0aecad69ccabb6b7526efbc0395552cc5d68e47bec00bc660ad7",
48
+        "img\/add.svg": "5711a740d20d8243b4fa9a52783689af96b3b01af6e422ec6a9f0aca16db068869a5a302e6960168d9c90e2dc0a69eed851d69e7f1bf33684304cf861f990604",
49
+        "img\/app-dark.svg": "cbe97fe9fe636790ea0b415035cd78321ff53ec93ab1276d4ef609555592fa13d09b2037c20e06bbb9024fcfcc0ebb806c89572b08adcfe4ee9d06c6466b685a",
50
+        "img\/app.svg": "010ad7cee20f3a256a24bee2482b6798f042a3992c7df5d56ba803cca93552c3cda2a68d1772e67143ce45207b89d397e34ba6909f6b8515134db64e2c5497eb",
51
+        "img\/arrow-top-small.svg": "3fba2fbf3a27f4d6b44d1c94da2260d025bbe682a3db18c21b9aa548f4878609770cdaa2e5c24e8b5cd97249647187b7499ab18bcd843ae7ee145def41561bbf",
52
+        "img\/arrow-top.svg": "389b15b7bfa8c90a79cd80958d1150538ddd0aeed875eae3a498b9bee8da3e63752fbc6c073cf58405fc35633a9b786e34b3ca1f6d234af685277aa8d439e1a6",
53
+        "img\/arrowDown.svg": "6fb30b189e848b26369238f7446eb1533327a4e99c70b699c10bb03088eeb7d47393f18d4f16bc03edb945f36cf13b96f05b763dba821c0b04b209cd81624103",
54
+        "img\/arrowUp.svg": "4f6a413d836635fd7e2e4d5846ee257c9a13e80624468e444ec906febfcf07a1c84f48d29cce730f29729cc8fbbbd3dab490e2192e5beb2707a6a4b1036bfd76",
55
+        "img\/check.svg": "aff77744fbd4e8eef8d91fd9e128e9e8be2830a93db9ba8d8a8277e78c8610d6ea5ec9678b3dfd2b8f2b4f8970dc40c4111e7af5011b0873bf461f5fbdeeaa88",
56
+        "img\/clearfilters.svg": "f554eff67f4c1440eb3865ea98b00bcde1f27361ae5888dfa7db1ed95d074915aaba0f6aed3f70d6d7c4cb5ca592dbc3f3175f958708e54830f895e8b652b499",
57
+        "img\/closewnd.svg": "38f6ba89d70905ab3d2c7d524fee42ce08f007622bb1256d04556cccdf40f549d39ab2fc455c878e6c318c03a8680d042c8e7d0dff9360a921e397e38567bf9a",
58
+        "img\/dots.svg": "e4a46301c4b70f3820be8d6906ccec273a96edaaab44d7c133bb58f5499f2fc6381f2029c27d0393e3d31e1cf10bc55ee98f05347fa6af3533cc74290d9bb909",
59
+        "img\/filter_icon.svg": "5258d0d0e3677c10a8ae5d8cc37318855e5a6d5071d5a61ee6d29aad7109292502d60571f2c5ae716295dd8f93a327c060ec7c65f2f9cbfee4b85086682a385e",
60
+        "img\/garbage.svg": "b76cde0659b7f127a810406d2b734f03871e3a7c8bc53acb723c2a97fa6ca0801a26cfebd4ceaa28d2ad237a67a222e00aafaecaf7e749cc8e8f93ae35a4c4f3",
61
+        "img\/garbage_bright.svg": "45bbad63a659b6add876294f8aebda1cf03790b0c253ba442f04fd9677c1a35795eb823dbb92bbf38066e8cdf89fb34671763dabbcdad4722aba3ffcaa21581b",
62
+        "img\/group.svg": "fbc10073fb9f5ac1780ccad2c61586512a922359b48ff76194bc5be2711ba99efcf9ce42a694e4cf1209dc78cf2bd077e12f98590c1fe1123260a23419cd256f",
63
+        "img\/incoming.svg": "c8f6e4c7e55c7fff5c74a87fe14e9f404fe5954a546949f148fd60cae7dd2e9165e883c34f1a3eb5500c12ae2bf281ab1607e04c4b75bd6322571ccf7e6ccc25",
64
+        "img\/list.svg": "2364a4ad93d0e4c85345a293f4f6b0e4135cbfb8b7b5e1ecd81d08affd0e0441439f9cd9e60da77eaa53052ef20cec20b49263e387b500c1fb4a3607b081e73f",
65
+        "img\/nextcloud_logo.svg": "4e0d3f0c371d668d83d443e5b1f69f0eedcc759092601d8fe8710dd97b16fd53aa3f9667bba7f305dc3aacfbc14e29b09b78da8b7bf6f41dcb83f5b16473991e",
66
+        "img\/nextcloud_logo_bright.svg": "aeab941556e29f9537508171583bb3309372866122c150c887c21d6a567c5aa06d2653db67c7151b064d4e2fa25f1fc63df21c786ede02ca5f40f12e5c1bad26",
67
+        "img\/outgoing.svg": "b5be7538df66570991b975b1fdca452144fdc27a14521dfb2ae4d0393d0f3b8abb6837458892e04adbdec0182ee3fd25ae33c6792457154dc2cab6e35bd6eb9e",
68
+        "img\/question.svg": "c2bb43256a2b8c43997dd6b40a2db8c811e3a2a28a0ebc11c8e87d71c21b8cfea3367a39730e6675ca77c9ec6e9adb4bab65cee474c02276f905b4477e28b1bf",
69
+        "img\/refresh.svg": "a95a19645bbde5e2146a3ec669950bc6029bfc6104886552eaeb4746733657ecbe4f9199e676ee2e9852ef0c5adb612d93e300e3fa9713fc611e1f8e7c1d5183",
70
+        "img\/reply.svg": "7e78973c9ef21f69c5138b036192a889350ba4333df42c3e343ab34ecc497574a601d5c6e2275846c9fd2adc525e209c006e9a957dff5d0c53fe1a69ee557e09",
71
+        "img\/sms_relentless.svg": "010ad7cee20f3a256a24bee2482b6798f042a3992c7df5d56ba803cca93552c3cda2a68d1772e67143ce45207b89d397e34ba6909f6b8515134db64e2c5497eb",
72
+        "img\/sms_relentless_dark.svg": "cbe97fe9fe636790ea0b415035cd78321ff53ec93ab1276d4ef609555592fa13d09b2037c20e06bbb9024fcfcc0ebb806c89572b08adcfe4ee9d06c6466b685a",
73
+        "img\/sms_relentless_delete_old_messages.png": "f8534ca040cd5e7d1bec0dcbd309742ff18e4cde8f978deaa2b50eeae8c810b1c4f605d941319e68353bb20a3b8fcf9e126d76e0b65a6176db530f8c2c9eae4a",
74
+        "img\/sms_relentless_exchanged_messages_popup.png": "7f64fb5e59222335a45fc93eb1ecf58e67635441d7768ecf3939dbee2ff3cb55f3e0f4c1b4e6b6e38744d86be65609ceca3e839538f185e62d98601218e16ee8",
75
+        "img\/sms_relentless_filter_messages_by_date_and_keyword.png": "d61047f211bfd6f51bb4222ec68fd13ec69af764964461f6e24194d99fab49c74c7e80c411c9be52f52e83357963a49fd7b2c0abe53dd60a145e5ef10993da26",
76
+        "img\/sms_relentless_grey.svg": "ffac810d151f22067a4ce4985b6c84ec6f6bbf7f1c0a8711ad4a374b838251d3681edfa8439e18c1fcb78160fcdfa20d4f08527a594c5080938aa611991acb2e",
77
+        "img\/sms_relentless_grouped_by_number.png": "fb34074ffba14dab82d4549162b4a447638c702b5e6c496f4bb7015b5456dbb2de919ec5c467c973f3299ef49b11e239a4ba4a7e78c4f306f49f11b6d78c19cd",
78
+        "img\/sms_relentless_logo.png": "bcc8bc7301aa9c4811ee875b5deb4ed21d9c7eca187970643962f0ae11a7483adc5257e26b307c41644dfef63ec82c4e61a221f133c62827e1d4418928c253c5",
79
+        "img\/sms_relentless_messages_to_from_popup.png": "a465c0c318bef7600610c345d3f88beee50bcfffa7b11986b1a8030f98797d73ab25f4eb1c773562566c0e0e02b69048f927a6da2a99e638f3ac09368b0ee0bb",
80
+        "img\/sms_relentless_received_messages.png": "c661692d3f1a766aac5e453a387f5d72cf374691010790f80087f35e78152652e963b937ff9f74bafc3513ae56561e4bae5409b5711cdd792aa09a10b7d17355",
81
+        "img\/sms_relentless_send_mass_sms.png": "277796f41a62a36683d9fc8f3b125dee29114be6e2cf6544c5023219c032f8ed2667ce02543b7550c0c72ccfc29f54d4a5e6d41d47c3dcbfa38eb8a48072c779",
82
+        "img\/sms_relentless_send_mms.png": "af7fa40084cb677f72f940585550c0a3515bec5989df70b56ed6e3a99d894b2fbc2a1faeb31135f897520d478f6aeb39ed5c3632a2375f4d8ca23a2b65a07474",
83
+        "img\/sms_relentless_send_sms.png": "75955a572f44c24c5e35a556de66d60f7af356d8c5b3a95134dc9165143326d285c4ec42a8154cc017fd4020d44a7df911461f00d2f3514cb2bbb6e519b206de",
84
+        "img\/sms_relentless_sent_messages.png": "ed145791dabad6478c05a9aa3a396e7a3422f64d90143b49a5df1a893f2279931df6945ba5b35b80291fd738066f4040dd468e4bee2acb630956af1d89c2a5ce",
85
+        "img\/user-grey.svg": "1128d96d0a4281591140149de57924e014a1d709ab97d351100c901569bbabc8c8834caf1a5932408b7918997547c323b8b9f4f410e1f03a4eeb89045bd95ff8",
86
+        "img\/user.svg": "d69cf4ee448f7ba5d46fcee24895e8705c297f078d943ecee1ea242b470c5e89318a5eb077c81e9c2a656f903c4e869298cc2935cf05a4a5f79e295dbf86df60",
87
+        "js\/adminsettings.js": "62e06665c2f4f45006ce43d79e76c4dbe4bea8004e059d3eed2924d7eb6e0cf16ec65c14b55bcd517e8fe4a2c4db29511513dcea6d2ef81af401981776441dbd",
88
+        "js\/arrowup.js": "819fd1975011e2819502cbe5bd006204122d5e73560f6f7fabe9c9f14c7086206e54c8b51e3b005820a1e2d9d29c9254ce2c1c8687285efc8daf3d667e51e738",
89
+        "js\/deleteoldsms.js": "7f967d97186690b1bf07a36efa4af3b593ef53c0efcecfb61d125aa15d077d5a6e69c703e3a0c0784475c5985272459c1fa9865395f7689838ecb37eb1b84ee0",
90
+        "js\/sendsms.js": "4c518a955141646d7dd8bf734402cb26491a57ac2bb87686d02757ed36193273646aba4726b1e0987a788e66a531fabf880b5742527969558466eee867b1f778",
91
+        "js\/settings.js": "5a20a7485be17f337c941551c8cc4de369ac4924444a4adab9f27edbee36f2536f7bab6983aa459dc31c43f9b3ab520a4d934bf6b06cd6c36878b4b145b39403",
92
+        "js\/showsmstables.js": "1f4906201fab2be28f45d557476a08394165b8cd2f709e7effdd7a88272e500555ee8ba48fe205693151c1206cc7ab7cf37f624d90105d552add8496bf6e0b7a",
93
+        "js\/tiff.js": "0c20e8d4f9f602ef497a26a50d8fd253abd55cf53afb0699638264550e931aba9b5b41c1ab0fdabee064046aab13b921c8d6988d76048f6c9795bed5aaac8aa7",
94
+        "js\/tiff.min.js": "c35f67b587aab62db7a3de662779a7b3264d70f5f856142cae88eadd1b477e474977f2b8c5ab31c16be002cb7ca9b52282e6de533b6fd79a02e6d33815919cb4",
95
+        "l10n\/en_GB.js": "475318da15c9eb934c4891702695fd9b1c9e98539585d2324b6702af6adc4a1a6adcb0e1e353163d5816de63fbccb8a0f3f71f0f2ac03c203d1ad9eb8eb56d35",
96
+        "l10n\/en_GB.json": "acce76cc12e2305761858a524874d691e463395102253d654c92f53c58b2794d185505256386bb6bafe55e16e291971fb14ee5bf9bdc495d0868016e75de61ba",
97
+        "l10n\/en_US.js": "475318da15c9eb934c4891702695fd9b1c9e98539585d2324b6702af6adc4a1a6adcb0e1e353163d5816de63fbccb8a0f3f71f0f2ac03c203d1ad9eb8eb56d35",
98
+        "l10n\/en_US.json": "acce76cc12e2305761858a524874d691e463395102253d654c92f53c58b2794d185505256386bb6bafe55e16e291971fb14ee5bf9bdc495d0868016e75de61ba",
99
+        "lib\/AppConfig.php": "c52269913ee80151397520bbebe4f0c725526910ce18f8717ba1c8016a5f4dcdc9a6f9350bc56c8a6b607ea342ee0cbe0f65afd9f03c31902190c008f41c9672",
100
+        "lib\/AppInfo\/Application.php": "7a4b185c9d8c130f7d3d804cd92099d38925e37b910f8bc2c433e3f0156f5631e2f952c7ece34f25e7139391f03158f3df1a3f60662d28699ecfbd89965b8cc7",
101
+        "lib\/Controller\/AuthorApiController.php": "7a561df46f2b78fcd4e72e6318b6ec7da0d54a5dda2b122afe41bd0f1bbbf55aa519fef11dd5a5779b09421f583e43b748c18771b0b2de9cad40f862a61790e0",
102
+        "lib\/Controller\/PageController.php": "07da5883ea41b3f7993a3e358a03a3db592a30fa81ea1ed0f26a234fcc3824a243316b76824fb9a24f40304ae945c48118dd4bed1f0d2f6993e479ab2c1dcab6",
103
+        "lib\/Controller\/SmsrelentlessController.php": "ebb0e3bd598739f8fa77109ad4c8442220912181b9f90a59328fd73d915a3b9bf6c66e7ba8687b93672b30804642be3cc16040631823a7e0192d9bc8becc8ee7",
104
+        "lib\/Migration\/Version100Date20211106192148.php": "96b9793edf72598c0330aed9f0c6c27ebf02287bd84b6b7a0285fc784bdf6442b560bc5dd2e55b464bb384a24831ae17d7ea144b0896d9b11cb82a27fbf602ff",
105
+        "lib\/Migration\/Version106Date20220813144231.php": "33f1f2953e038350e37c670462cc79fa48ab3a72b595f5fce970fdcc6d7eefa3401722da4cc532c7114d0c8aab7fbf0281afb374a695d5c1c1b311c30f64c9b8",
106
+        "lib\/Migration\/Version108Date20220823132408.php": "5d94388496cd88cec1dbbe67a2e9d6ae6fd5db7ed42d4bc737710d3c51ad4d8ad29d53a62739e05e2986e2d4c96374f4660a53dd7b7808d30e44e5c605105971",
107
+        "lib\/Migration\/Version114Date20221202011625.php": "920ee001204afad537bf2b7dbdb7c78e95b4ad0c79f5f693bd56347a1df91045cd83348f99e2ad714df2a735cf1a1d85aeb385c675ef6e90eed26f18b0b7d344",
108
+        "lib\/Migration\/Version116Date20230508212745.php": "556137e5580eb33beffbf6198447581b71de677c2a2561508c0d7f2f51e3ab7ca9feb0715b994a2753616838ad732e01e6cacbcfb521eaf559fb40200f0594fd",
109
+        "lib\/Migration\/Version117Date20230509183517.php": "dd289fe9ed0947b1174390dbd921ee696b50af9bdb360585376a6d5334e390dbcae65833c13c332732309f8fbaf8d83d047df6accb8118c9e4fdde8370db7b18",
110
+        "lib\/Migration\/Version118Date20230509194216.php": "165c805c76bedec7f48811fb4a83685287daa07660cf369b952ed2dbd9a6c0bf1bee2b78d3642478acc37ebd597f0df7d9eb7035c047acfc69146b664afdd286",
111
+        "lib\/Migration\/Version120Date20230520072431.php": "322eda5d5112d5e52a466c91ba02c40f1e77231c627c155e00cf6a924fbe16b4d6cee69978b0b3789c5daa03dfdb3fbf0f33b42fd40811aa366c7a227db4c31e",
112
+        "lib\/Migration\/Version121Date20230523201743.php": "d4f5e1520213a4f0a1d74c6faa1da8a4988dacf8d3f3c7aa8bb932744789a366e1758e2a9be14c7768ca7114ac0e7588ad53b7a9ad6bc1a45da5ef22806126b4",
113
+        "lib\/Migration\/Version123Date20230524182156.php": "7bc033f8852ac9b79e15bea2e13421c603acfcc443304bd36cb0f015991a0816b90950e6b45a84ebe5e03e92c4604e3473dbc90bd72810166a6a20f97eec546c",
114
+        "lib\/Migration\/Version125Date20230603224815.php": "430f98229247d0ca7e3c96f44d810e84a04a9b971c42f645eaaad08b213ec87506b4253c013b47b4c06d7f595aad414a17e3a9078b0fac9c9ed0d980bc39b4d9",
115
+        "lib\/Migration\/Version133Date20240215094712.php": "a47381d134e326413d2b8214f602d0abe5de30f99107c3f68bc2959fa6a601426d1f3f8f5a40b2ec7e297de696234918aa96eee51dea504ea76dd9fb63926958",
116
+        "lib\/Notification\/Notifier.php": "87389f3cc99cd6e54357f7659cea534bddbefb9912150ccc9c38ee71606aed37831bae0dad3670156813ce50493dff9b2e7a4d838dac043bf9c7844879dd9f44",
117
+        "lib\/Service\/SmsrelentlessService.php": "9a6b4590e797d7f0ff1648b5929c28ed4baf8364d5b455fbebcb52d60a5aa58e4f26b3a502509cdadcf65d4cb139c33c72c64f36c73b059a1f23f937b8d2a432",
118
+        "lib\/Settings\/Admin.php": "e4e5f6e8fc5748b11c90b676326dc228fbc52fe1f77a07e7b7460c6dbf2a8013b5e0b0f9084aac3f941478ae6ae75c47be17df3d229d8a998363b9a1d289f405",
119
+        "lib\/Settings\/AdminSection.php": "1c8fb26e8347d67c69af385b0aa33be2764135a4672b872b6c6d41bef3eac6733ca2796c393c8ff334ff56accd7ed4d4c38ca50baff2360d8d8be02b9f8a7c08",
120
+        "lib\/Settings\/Personal.php": "db6fc80342c865841edcae7d2cce5e50d04473a9ac47e26c2daabce493bbb1bbb922bbe9eb7353d759965506dbf1b4c99ce8e9c93f5c43769e1064cba19f95dd",
121
+        "lib\/Settings\/PersonalSection.php": "e65e1a8939e3818e7cd295ce86581a603b1e2fedb732ce51ed1fce62cb61ebae9b93742b1d923f08e14cdc6bd5cf2818d47917321e0aa1736932830c05a81682",
122
+        "providers\/Flowroute\/readme.txt": "25f08fea0f30105e850dbf07bb7a9351e47883640dd87d26981cf50f02ab5af8ef59dbd1fbe5e4127c0e019e13ce036f9414401b9d3f3a924c4125c291e53446",
123
+        "providers\/Plivo\/composer.json": "2d8def5ce9444d4bfe4ff32e008e6aeec924efd40e0cb61f3a72585fc4cf89e7b62970e796d56ebdd5d2f6378f39d3ad540ffdd02c31e2c4daae9b760482619e",
124
+        "providers\/Plivo\/composer.lock": "d9a2b89de334156eaded5ca4cdaee9b53c05e5d78584faf000a141692225a1bf6a1dd9ea6259bee2158ca7669c4000b3c366703fcd1f55a835278aa9f653c7c1",
125
+        "providers\/Plivo\/vendor\/autoload.php": "597387bcc320be22e8b0060c456fc745d8e3fbb06cd1cfbdf093b0ee52aa30cb7e4c31d6d8c38450f52387c0cd5f9d0483e3976611d96f391f5651b71d2095fc",
126
+        "providers\/Plivo\/vendor\/composer\/ClassLoader.php": "2b6fa585122ace1ba816410acbd8372cb75329917aae6363dbad48e396cca581452616e1386a2e445a8fbb0e461b988279103f4f89adf704bce7726f761abf0e",
127
+        "providers\/Plivo\/vendor\/composer\/InstalledVersions.php": "62b61a5303337c975905fa55addb6b1157034fecaa5fb3b5bad251ef7fa1b1ba840308f64fd2e1244d2098b7f87431e35939a153298530cdbd82f81b99cabaa2",
128
+        "providers\/Plivo\/vendor\/composer\/LICENSE": "f3bb64009f41a425df5a9bbab53490f0eb9b74fa8d6aaa2f57efb928edc4ffff330260666edeaa04a91fed708c3663371cf01b284f3a08d6698aaef7a23f355a",
129
+        "providers\/Plivo\/vendor\/composer\/autoload_classmap.php": "1844f7843fdaabef42d1d9e4c09f92f51a5ad45b26d44b34a2aa9202a183489239a0f5ee6502f302b169ccfa3a4bea7308771ca02d3bad96095b5b2194a65377",
130
+        "providers\/Plivo\/vendor\/composer\/autoload_files.php": "c0eaa5b28b83539deb67f24a98ebff5ac0483f9117a72d5cbba02e26f1f18cd4c93ebc23786047ee61eeef11961c55ae6cd4d4096a16f18a19d2af49a47820bb",
131
+        "providers\/Plivo\/vendor\/composer\/autoload_namespaces.php": "0ac6bde683c053d62b7024686ecced083ca1a326d5346a248b1a058ac74a5af71d515d311ce76df799a518027f734b80b9e7f6e8022a9556c0f24ce90240d822",
132
+        "providers\/Plivo\/vendor\/composer\/autoload_psr4.php": "91bffab80b2ba961f206bf3008a7380f81b7cac7b09afe4bcd2d4787d8b4c839ffe2a67442e04010918631b1c76b66304e7d7bce76371e741b444f2ef527355f",
133
+        "providers\/Plivo\/vendor\/composer\/autoload_real.php": "2ff5b7a817e3acbf585fe506b11345f6f3ab0f21c0ee96c67037f09de6130126d4c0e728ea22508192787a451322369197610726f96f32a12f91b7e48cee86a1",
134
+        "providers\/Plivo\/vendor\/composer\/autoload_static.php": "4fdf5e58875a6dc6bab4aafefd254cf3504f78feecdeda5fb431a56f84b37d2cf8fab8e233ecaadc2667f1be492ded264423f3200e1095aa507172b0dad3f60b",
135
+        "providers\/Plivo\/vendor\/composer\/installed.json": "0365a8c8cb376a0b3ca8cdf63147012435d2488c5ab585db3f9e0d926b588887992c1c8cfe07ac187f5f72afa9a3db936c6885d443db444147d7c87ff0f3084b",
136
+        "providers\/Plivo\/vendor\/composer\/installed.php": "923c151f9cca2fe9489aa4cfe04053d20e1923dfb388cc6aea2486557d77284fe6d9d2a77a7acd94496237465f03b712166a2f2f5837ab13bbb7f0aed8d52552",
137
+        "providers\/Plivo\/vendor\/composer\/platform_check.php": "49e79f2c7c1c32796dfef02f64feda4fc8fc5aa05197465fba579997d332cb9dfcad3511efbb34a32a2b2c8d8901be4ca39867026b2471fb17999ba840c3c340",
138
+        "providers\/Plivo\/vendor\/firebase\/php-jwt\/LICENSE": "6f6cbdccc57476f5386f5336c1efa105b4116760a329ae2fedb30fabe1f34f7c1a3073e7f711e07284c8b57b3b8ab6dcb38ba8d71f6835ac024ad524ad658f94",
139
+        "providers\/Plivo\/vendor\/firebase\/php-jwt\/README.md": "8f3226941b2d676aa31b66f5a38f6fa78a4073ec7ea6d6a3aaf0209072cbc8df2ebee65f64460e350f499f8448542443f9859db75f927fcbe70f1f59384e1a70",
140
+        "providers\/Plivo\/vendor\/firebase\/php-jwt\/composer.json": "82e17e8f606504476175a3c5116bff37c3d58faf5fbd9590cc4047f787b6aae79a84c660bf2e8dca453b998926dec84e6d5bca5d81b6817e09d99c6774cd04e3",
141
+        "providers\/Plivo\/vendor\/firebase\/php-jwt\/src\/BeforeValidException.php": "8aac5fb14b6d94bcf048a1cd4935af09c25183e74eaad8f2db19902f1f017a33261707b12be8080d5a662bd01d997d4d5805cfcdf3127f447feb6ec6b971f563",
142
+        "providers\/Plivo\/vendor\/firebase\/php-jwt\/src\/ExpiredException.php": "7cf0ec0dd02717f5152abf5c01979526fbb89f04c01802915745097c8606e432b41a4de5bf92b7cd1543b37a939ce8e133b7622f29cc48798c321654dfb94a3a",
143
+        "providers\/Plivo\/vendor\/firebase\/php-jwt\/src\/JWK.php": "3f134e7503b44f882a92a699dc4cbb4d7415bb93526438e4395cbe877ab2da700d3ef7a8c037d7d2ffabb84e20165f93e338bb32c2bad9426e63708da4f842e3",
144
+        "providers\/Plivo\/vendor\/firebase\/php-jwt\/src\/JWT.php": "9e5e21477b0495c3cc6fdff79d9b6acc136c0187d732cfa4ea438d9802be4642c2fe0e76b288238fa29bb0a8e37e31d57546d548519436dc49de467cfa704ed1",
145
+        "providers\/Plivo\/vendor\/firebase\/php-jwt\/src\/SignatureInvalidException.php": "0c00a3a08bf4fc2eb675fe8ad3d8cb732a82a8f88d37dba5e510ec798a49342b8089098dfae1f1ef1906e62a4b8e465fb7b4c6d17c9c0d8e66ba33ab271e5c88",
146
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/CHANGELOG.md": "f99b50bf2d30b8e842d2db14a28068364b330b402db7bb1fe87fd4e1e3a9009edb05a519a4c35be68ba99c4c334680ff52ff0bebb84ab99de8814959d34e9c90",
147
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/LICENSE": "ed4199d68a412c0515450194549bac0c6a6d838b3950c036bff6c97457fade76fc914d11bf008321b3e2622ef0a3c14da0bee2f109529cfa5a5fdc11fc6452ae",
148
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/README.md": "dcb463420d7da1805c5cc020988f60c15fc5623a2493556ba4bba63d431c21f0584c1e65f27bf0a4c7962074aacf40d763981f878a10e12327cff9b89204ae57",
149
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/UPGRADING.md": "4f2540329c6e06bc0f05a574b0ce5d77ac3f7fa4032371665dce41a766cd28ee12a0b7803ca507faf005f6a3ec5107a60978b69a4fede8bc562333b736576f55",
150
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/composer.json": "8746b3c8b0fcf0ede926b6a60b4d34e7a3e0e9664aef67b34e7e238c25179d22ce599e8c4a580e9f3d73122a0c9b373b87526874c947878ab339e662b03c150d",
151
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/BodySummarizer.php": "649dbacf3be500e6171769c18b1eec1888bfe831dcef8464ebce4461d5fd337c60a200d3c89f9bd7c2714c0567e5e220b31ec2970e7a013f914123824ea324a8",
152
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/BodySummarizerInterface.php": "d0a1271ad03136dca5752c0dfaa7fa678c6fb03890be828780201cd9fbdc8169ff4fd7c17867cf82ef1672ecf0e9f871f682ade1a8ff37e7b84d24c572e1b962",
153
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/Client.php": "8fc98c3490398476a81f660a0dda38306acedaab2f662f762881c11f98bab8b5194ea6c05477bfb2676848f54229087df8fac0e6aacec6499f2313e09b940ea4",
154
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/ClientInterface.php": "d1ab53fbb1b6695e6537050421b3a749a7b34b3184015da449a1c76987fd6944bcc1c4cca7247b98b338926af89fa477f9be4897e6316cefb2c1656520c3ea2d",
155
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/ClientTrait.php": "ec1e95b2f1c56e4443c6fcf695ede88e02f1129b7027287f968a0ef2f7debb7533ce2371a27b5ee07f78818786b0a6d1b3d2f8ce28f44f4a8f7e275bbd1b6727",
156
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/Cookie\/CookieJar.php": "3fa0964d59cbba956bb47fe103f02e4707a2a6ebe5a60dd5c33f59402a090b6f0110c2795b52f961f6ddf338567382e1248f1e27bf2d0e2033a43efd15e2705c",
157
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/Cookie\/CookieJarInterface.php": "a3c6b9138e285d6c6b7521dc7059a04e1c80bc0de7a925c93ecde6c95cb7fadab91ee05e9594d6b891872a557a1b98fc6717ca1d1d46e00992c9cdcdb934a71a",
158
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/Cookie\/FileCookieJar.php": "35111b9229059f54b537baec960b8480d5e3caf2961ca3e7e45de3fa5ad5bd0b0a91c2c4231f6386a4966bf9d97aa308a7e444000dae9b21f8c58b6832dee68b",
159
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/Cookie\/SessionCookieJar.php": "9cf11d2908913a7555e9e190e6a4ffb0f0e26ddb3d141faeb0e7bafaa6f0b3259119ce6febb6d01b5a7f5a3193f72a099f08ea45b5955bdc7120bfd4857879a6",
160
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/Cookie\/SetCookie.php": "7d6c4c14c9d652c27da23923cb577fa999e24f81c1b82f13fa329da3eda3373ba7a832b72d793d924fda9d6a3a02cb39db97e49e17feab3ecc93f395e614d44b",
161
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/Exception\/BadResponseException.php": "4b7a572e9796b8043d56dc6650709e59bde237b3bacab1206b807485cc850ec99dde86892696d73121c345f1c88a9d2e879dc91be2cd438defe2609e521011b4",
162
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/Exception\/ClientException.php": "0011418b0cd07eff70f99645a008c30e9a6a90b9ec396e8cf70ffc281140054bf313eba40d97ed34b59e04e5fd6712330d34268353493d112b8029c1c42e5046",
163
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/Exception\/ConnectException.php": "bca929720f3f8f4484899b18b40f5d4d40ebc4105b316679a9349b97200c74ad2ae6408e2362b4639bcc4a3150fe63ca1e08bc1b159c51744d76466c41203c83",
164
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/Exception\/GuzzleException.php": "444ae2d2847cc99d9a3895e2d23f0abe59bf0eae279809f7a4983e34098ee0a0ad7408d251df821c4029621060aff1ea0dc890615535ea4368e5796151a767cb",
165
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/Exception\/InvalidArgumentException.php": "2647ca6c297960b01b29435db7522ece3a997def6b3af71e26113abd43ca4493501c130e7767b845db0e723f9955164ce33664d49bd67a45bd29d270a66e0e3b",
166
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/Exception\/RequestException.php": "b0b3163e4eb96ace90c03faf9406b89ae21c7cd5fcabe78035d5d9e1e7ba0ff72bcf31b877ce2d5cd38e940cf0ead52659c3637dfa3567745fb46a11cc9de31a",
167
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/Exception\/ServerException.php": "9cab599fd913d8f0bb1b8f448932ae0b5c5b1cd7d83fc4e1e4c13fec29b0a849a5385a6c40183b8dc58404ed020227b9ea4483ac89d135c6c82e4c7985604044",
168
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/Exception\/TooManyRedirectsException.php": "99c4e6f908a5dc03939ca083232cf48cecd742616e00839ae25ca173ec458e6da10be2690b98588b76e0f3c24ee7f35c09ed5c848f9348c639c414aecedf6c2d",
169
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/Exception\/TransferException.php": "665600a8617328454b70a43fbb72c81ea196584dc22e10324b3c861974aa55ff5867b30b86a65123f1bd4fece75049a9f6c4bfeef5410a9f29913d350358178b",
170
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/Handler\/CurlFactory.php": "1dd7a848ab73a8db9354fa2f0461a995320ccb677b29464812a484730a85f405d8b6c9b39783881b299328cb8f99e67b9d959b00672bf60a4559b136fdae8119",
171
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/Handler\/CurlFactoryInterface.php": "0d063ee120e0ff6042a58d29b109bf6573494d427e20184a4d448ef31fe0cb0cedd60bb47c7289d5f6e1027413a28f9f57921823605d4f11086da5c9be8c0902",
172
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/Handler\/CurlHandler.php": "ae0388a0146bd0cfff1c597570f58acec92876d3d01298e1988dabc717ffd76895b45359cafd7bbc62ca1fb5e7e96fdab70697a2cb469c8c5d0298aef12e44e9",
173
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/Handler\/CurlMultiHandler.php": "d03d4a374657d671554d06e5622eef0d1b06d0a39a9167ec6f894ee28af31defe1d4306f937376cf5997c1421643e08e757880e45a1c9c10959c967022160f96",
174
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/Handler\/EasyHandle.php": "7438c054921687fcc4bea6ef6b49aae15651a95cced2cf73ffe46bb15abdf924afdd4784e8d2121ca851934fafce69d3661f1a792e6f2352cc5f5c1803ace3de",
175
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/Handler\/MockHandler.php": "0d8e2e43e0b8079f20de6b86c241afdc83bb5bcdc5a91ac47084ffdf2a3904a79e5db6fbafa4715785ded8fb90dd8fc418aa05bc0fa8c52220555720f81e827e",
176
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/Handler\/Proxy.php": "9caf11da430da351eff6e9be0a1e8e029bce41283a6d8215e2215d6abbd3f021018564d1e6717f65f280703d5e4dab78a2b522042d63c5a9cfd019b0bb0aa4f9",
177
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/Handler\/StreamHandler.php": "e45738ddf123fa57df229fccc94622b9a2ad5dd9bf6f65d24756239b587937bac9b7a37220e65c55f2abbd7159bc16ac785893d4aac5c192e6422af4fc4f1222",
178
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/HandlerStack.php": "900b9df966c3c1f3aadc45bd42a81e8ab153c74d0eb90cb3c8b2f9d46115353f45e5bcaf0eaba1281ab98dffb3d136a0c0fa0058fe73d906eebb741b273c150a",
179
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/MessageFormatter.php": "99460bb55080cbc7e08eb6f1b3c8abc71c38cd5d6e04422bdf8144ca554e7d7de29fc5d5dbf7aab5f7440c4ec9d779d684f8194f90139a1ece1bb086f14e3cc5",
180
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/MessageFormatterInterface.php": "609462659ab00682e7fdd1bb56aed5ad3cf54a2ee3b641623175b9dca0136b4e1cbd3cb0541526ed86d05174a18a9333ba52a9e50f4c05ece55cdc636815e385",
181
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/Middleware.php": "42fea3a5bff7eb363a7af1f85a21a9322aee8d7e343295209815739f8bbd5dc372f14e3e8c5454f7650a3b9d802ca25fa069d64fa16b0f5d4d48c3d626ba3527",
182
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/Pool.php": "a6d17779976754d7c16127680ae32f8e45ed54c3ef4a2a6364a1e4100ce732b8494b2848977ba6b2bf6fd296d7a54b30a2f021cba5a88ddd0d1e0f3a3712b9cd",
183
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/PrepareBodyMiddleware.php": "268182133f0e484b56fa23193d20def23166eeabcc2fd9626b17cbc20188d76549adaa4c768df695b787d31b2eb26a5316f0a3531ad3ed022aaddf0574fc2ac8",
184
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/RedirectMiddleware.php": "38bbd75b92a6764b0502cea113e222d5cce7abe53c7ea0c01e441fbbb6b0514f2f54388ff14d459ed611925eaf9b48c0aee1b1fb41892d07d1b260734a1d2afb",
185
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/RequestOptions.php": "239e524c17dadb296efbd8b9ba82b94ddfcd90c83377fe4bf2890dae5dbc62f58032205274575f14bb2e745112ee59bb559936b992d9a227dec00f5b2e32c03d",
186
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/RetryMiddleware.php": "01236bb2265c0761148ccdda7d3668c10f9539119bcdcc36f10d077ca32013ca0169938d6f4bd0703018f38fac53b2bd34e873a07d8e5287c26fb64b7284dfe8",
187
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/TransferStats.php": "4fe882f7f801ba55a3934e00d81aef09edd092eadef498f3bb424f7f32dc8d568940806a9d8e80b1b6c768cffd41ecf0814a0bb366195b2400f08a8e310a8c19",
188
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/Utils.php": "c3e52199a0a1755f52b6902b78d008de10e33ff8b93242a709d7a12e8c05c1c2c09c2874439606f0f3ce6b353bbe3b8ac385a236307b428fbccc078e1959c7c1",
189
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/functions.php": "f45c62cbff0de0255f4f149ee3e93c52bdae44492d43c9314a48d8a793ef028f8a8f704a2b28c5b84491687c3b682e9f85c4ea61bf63de56c6cc6a4ba8081ae8",
190
+        "providers\/Plivo\/vendor\/guzzlehttp\/guzzle\/src\/functions_include.php": "058a92f735b5848dc18be383478bd1659a0b578beba1dce5a1ef3b7a0b6b5f643e2f222dd72ed09ec72e8a5c5c9fae9757979f7c4016c5654bcce9d7dfd42d37",
191
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/.php_cs.dist": "4d42019074dff2a1a5bebfa51568de254e5128b88ad309bbed5e8348ef213035cf3a4da66ae6753354a0dcf6ccc0001bfafa2453028bffb3548f2ede26c30177",
192
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/CHANGELOG.md": "0c021cdbfea029de4a20511445e64d0d6c35400025f1361cc913754adce9b2dc16efeac12cbdd489ffcbb76e95f91108dcc557fb9dfdacc99e5bb98f20b55b43",
193
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/LICENSE": "9699a00cb2c5ebf932515e1232b83f79c944f8100881df096de09e25222fa01173bf24d9e083db7d9605d1e4f5dfa14c726aed52c0fc2499643714a9e64c4cc5",
194
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/Makefile": "a350f48cbb68a05cd07f787522193851f9cdc6b2643e34eb502fe261387d97e5ceb8499a22b20ff2fec5d7352ff239a952fa3b129ba3407fae871683d65e9bbe",
195
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/README.md": "1ea705deca28d726cc65d0f55db886545b9f5309ccc085bb482f627a0ddb5f8609d6635f65686e3e26b9a23cb8bf03b3e8d02a26d25eaf8195dc6c2cc93be0bf",
196
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/composer.json": "74a66451bfa422f886266ff300b4ca5f7b0ed62199293635671718caced457f6eab5b8c9467f24e999762f56368fb35742dc0adaa35a233d32c72783112a6c50",
197
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/phpstan-baseline.neon": "916bcb7d298578dfc4770a3c49ee558eef9a20dbff8e3d097506379c8680917b08a8f96f2b59d96b1b56b1ccf4a5478c868a2da504a1935956db70f51528494f",
198
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/phpstan.neon.dist": "ddfcf700a47b916ed1072c979f13d6d51327c9bc389c49ad264ba23279b01151b90aaeef0a81a13eafd40115d407ceaf471c20a61b47f1b4796f8adf3c1ad218",
199
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/psalm.xml": "52c09c8b7daf6d90db16a5ce50b7a8ce15c1ffa02265fd1d4b117cf717331475245bfd4f2dc45d3990d67333988a11081e13ebf783bca8854a1df9c1b0cc9cfa",
200
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/src\/AggregateException.php": "97b6e46aa16ad26a2b714129b83d933cba02ec7afcda514ef67c5027cf5b9b93a5d7cbc72560307adf294179a4d7b86a6da9caa835bcf5be17e398501bb88fba",
201
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/src\/CancellationException.php": "b958ade84fa4e6c7a7efed66dfb6a7f83b9743a9ac6581276eb99bcab667ebcdfea92a9bb114d086c5831d26abf7f6ec3e03254067e2b29abaec995e28cbce8d",
202
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/src\/Coroutine.php": "d1c789e47536cf8c9db52acf791bc6de0d61790856a78f0cf6a9c98a1628d2c42cdf9e5e94e05fea802a099bd3ae3c65b790f2fb5a342bd130654c4cfb4fcf07",
203
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/src\/Create.php": "a3651bfb1f458675c58397460c8534c2819404fc89422467f119de4cd80147177e462a9965bde6a75e74e4354c3c6935cebe1891e6a53a1bb26383f22e9dbccc",
204
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/src\/Each.php": "e57ea03f69e1680b56676ca1057e8defe7eaefeffb456b636f3cb32295eb6be36073c7a9a621f656c40d5661c0fbfaa3a632961d82ec7f116ab7fb5aa9db196a",
205
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/src\/EachPromise.php": "c7d79757cca80b7352ffd12a6743a515255e4a89764f65067035b16fe39c09b6dabb833aec3fad3cb741aefd778f620202caf79e98b86095c6b252f4e555bbcd",
206
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/src\/FulfilledPromise.php": "952eac7f7cc150394dedb72ac97e624db8156ecd41c8afc382ed0cf8e4c2c6c94879b7ddf6ff76608c6a95ef30ee136f44fa03ab9f5ce4b7fa01bcd0c7e7574f",
207
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/src\/Is.php": "894b3c475b5a828e442745507fae4b35bf394fc9fc93905258f9736a67112c321b1f3e353f8f3fb84e8778bff67bd9d27a6fd5ab6dab3218a30d82b8fd14ae0a",
208
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/src\/Promise.php": "bbfba94124c36b87941e1548162708a5543f156d64a8f465f78397a02bdc34c764b60f73d5e77a3a2e48727f4cbd91f60b9c1cd47c0fe205994c4ffdadb99c5c",
209
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/src\/PromiseInterface.php": "8d8d1d9e04d75ceb6d3e656794fa93170a3b1f9c2dd3b53ba6b4dd3e599f880599cab0b1ec15eaedc1b26d09d6c535dc9fe92802ea8ab1ed5927ee8cda7cb9b3",
210
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/src\/PromisorInterface.php": "1058176a68078d02c288528673176648e38d2b8093e67b0984d73ebc710c0bda7019689303b1f064726cbbfc9382e733443e9d5443a77715ba40bb798ac79e04",
211
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/src\/RejectedPromise.php": "53914a46ca238b8d079333f9c71180aed015a77bf765cd2793790dde21fa7fcf67dcedc5c797a1d7caa06d788bd9631628712861b1185f3cef9aa63260aff0cd",
212
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/src\/RejectionException.php": "6dae5e0b0b47538e5c94a3d4890623e3ec41be8198a1d00ca84d77f32b9d074cae13e25ea90e2af614e802aa28271def466e5ab623c187df49425cdfc5bc05f3",
213
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/src\/TaskQueue.php": "431a73762758dd08406a41587115a11e61f921cc01997ea71efd803b2e3882b9cb7f6d89694e06ecd2992f2bffa38ba55d631dba7fabfce3b84d68dd4913a02f",
214
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/src\/TaskQueueInterface.php": "f0b2b36ffb75337c590f82d3d7d19a4caa4eecd6003c0bec7ef935604dfe35f4e960f49da7115b3b3cf65c61d04bdf258310ae1b4f4b6cff4eb09f52626adc11",
215
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/src\/Utils.php": "9bb1eebf4d0f43bc47cda6f70f08b3fde962355075bb87d40ec75d41b552c262a79023a72e2e8d776b6d0db1ef1d412e398ae16d96476aa5c72afbdab9d5a9fc",
216
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/src\/functions.php": "b756c2bce2557e9c6b8db2ebfb026354418c93f54169d1e9249478532bb02e1062c30e14060a3bae195098c74deb4f7580943aca944a162615c44139acfa7861",
217
+        "providers\/Plivo\/vendor\/guzzlehttp\/promises\/src\/functions_include.php": "17063296fca8aa655e7d5267abcf04051cd58fab5a7ff02530e1becb5002306252d5ec55c82461cc51f62c881c51dd80da53ed9d90640b6d0dd56d5e8f819022",
218
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/CHANGELOG.md": "0540da857957565d77741b846932c739e0883751660d561b2a0990a7cec8188573c2d31400cf9f125d1b6eab482455d19f30a8363354341e3c54088a0c418e7a",
219
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/LICENSE": "5d25479f1c9c0b802e2944e029d7011f9b9d3f7b37f7c12eb77321ba448414f79b0b254c0846d2e5e1b8826bed85d7c377803a4ad5d5afb288f220c761822043",
220
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/README.md": "b9759cedfe2199b2477e95fc0770f35ed6a4a18c6e6b4b4e30a20f75945505dcc76834e20e61e3aed90fd790c677536bb43f593de8a68558a200000eca8d0bdc",
221
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/composer.json": "27ad0b2937068e201fd0312a7dcfba706a8a318ca4e09d80f29611803bfb28d48433ba5f2b452da8bd76fdfe2b9f073f81f2e2cd6fc3e4223b20637408f6c836",
222
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/AppendStream.php": "d94d352d6f640589e84fe2aae0bd20880c4d6e897a29a47d4dffe6aed4d852fd5df274db2e68124c7f15b84d6f4fc684873fd03d003db39caa61b024b053e396",
223
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/BufferStream.php": "eee7de67e107fb33e8f97949743726a30e8201fd874490fc93870a410b1e0e3a059b75dda972b3a844b8c739b9b768a73d65c61bf8030589d0d787aa26f70e8e",
224
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/CachingStream.php": "e9b1e3d5e2bfae610677b9d216643be7b2e8b97cf661bc5c67631f994df0dc88a9a9ac7bb9dd68fcfd2ed343cadbbae227a8a46baa3b732733497e24f1338be7",
225
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/DroppingStream.php": "63db37354a2eba98b768f0929ee9a4ffbce1647a79cc9aee5e994cb693e53cfdb9f7a0fc4c32b68b46c64b39438b1c53a30532f5f8fb442f07062a6b4861e39e",
226
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/FnStream.php": "bd25e2ca8ea196a5e876c5b9d01c6f2a27b206f7ba05d047cb46476c52191a594f1280c7435b6429e4ea411fe5fc01a2388e213df26d27c5ae5094a0d0f2d619",
227
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/Header.php": "27014466522ffca93b4a3da6e96a5e8501f11691f7642a2e5091f3d0c1b146789ea41fd7fa1e3948f264926e7b764b557b1b564a95a7b5cd56c17c8ddfb6b7d1",
228
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/InflateStream.php": "e19b69eb2f1d2f8782f7285414095ea810f746d02a447badef5ec7185623235f17f5689682b185ba124e71a19b0dcf3d36b64894d183e25edf27f1d1e34c1c0f",
229
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/LazyOpenStream.php": "8c262a2c574767d61a9eb084d6848bef77d047601ec5688a90fbc012d5349d9b4ea188444fe509c8ffbcbf6ecdfd839a461505ed3746b6e1c5283860f7fd4a2d",
230
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/LimitStream.php": "81a43b1ec261207c1a52faac2c5099a429e43083bbe0c9099f447859d2ea12a45d30e7f0b5a994696084b3c59401bc28564685c432644caf6a9d8b9669404c91",
231
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/Message.php": "4e9b857c226b57e2d2faea27643d6f213bba65bf158889a528fd684cf1acce6f480805d04da39a32fbd25be9fc51c4f1a3c1bbc9e92f3707fcf33a120b2aa256",
232
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/MessageTrait.php": "367bacfe383be2caeb0064fe80e5f6b138050dd4189bb65ff82d8f86d0b1b604090b61a2473d7e80c733c395cb893fa9eb2dad0a63a353c19da32e940a1de01a",
233
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/MimeType.php": "98467f19beca7d4239963d4d91a7896d44539c13a5c694c4aa8ec68f3b57031367d1cddff19fb51c389393cd1402a574c9afdc448766c8807228d726796d2e9c",
234
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/MultipartStream.php": "5bbb8f71ad1f2f421eac8c0d40c3a18372516e8ab8f2bb3f917871bec9aef0eafbef930902084aa3ca64a8ae930edb1f2befe1e6b49dec387ea239c5c475c099",
235
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/NoSeekStream.php": "f003ec01ce15f5dd56200396a84a2c94a1b134d320230983ef91efb1abc770827018894a1b8d1f3a68c2aa481e8f0bfbaec4c568d0b0fe251a61f76ee22efa38",
236
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/PumpStream.php": "15192b83cabf910107b30bde59197618e524aece85f9d396dcd8459174fe50a1cb82de51e5225b8e6ea64fbeec7b4d94f035bba2ed893efebb660105021fc98d",
237
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/Query.php": "8ace1f141c08396103431803ed35e1bf247fdf7f7c7b727ca63e58a1cfdd7e353a6c266c8a7bdbb863e5d290414ea630bbe37f55f275cc5a5b946b794ce01740",
238
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/Request.php": "e0582b7b304fddcd81a214bd8ecd4db301479eddec3084b18b822f5e22fbc9d1fe3f3d2f6ba52959619dfbd0e98db304b2400e67675fca41f470ca6126085da2",
239
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/Response.php": "32524250d58fba5c152472ed37160a9aba92c586c9b2a6bc55f97134e490636189bc8708fd8ca4145478a5bb20ea51b5bc417fa8d61ab08fab3479a04c4506e2",
240
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/Rfc7230.php": "beb2f85fd643c3cdb3c92b401c4df1385bc6fcddf7dfbfbed88396611438720a1b86ecb9b913472ca8edf1bd9782a3692b2138195fb366ac1b8a7f1b0b81d390",
241
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/ServerRequest.php": "f3fead87c83ce2f73b2890ec79cc620f319c59ebc41a041e4b70b38bb1e412c928fd7ff0f10d96fffed841cdc1ef2874d5ddb0e7cfbbad3ffa81ce7484365c05",
242
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/Stream.php": "7d108ed410ba89cad35637f837d97f7ef53c43a4666d0502e3e7dc4aad06e7bc365f311961d2bb8768faf9d9c6d64d09e080aa9bc65638084a127e7a563acbbb",
243
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/StreamDecoratorTrait.php": "e1b90e1d97a4a1ed1eb1552bcaa9011f79733167b7e5e3f2af8cfdc54adf0d64a414ed630ec74418020fd8ecc7c75e43db6bbe0fdb9ec6d3ea928bd3bb3f4561",
244
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/StreamWrapper.php": "7ed1833a91a1f56b743172192b7ce4399928b261eddba6bdcdde958bbeedeadcaadff4fe5b3913dad0e4b2cd9346f47b43849cc65bbdb839c9d9e4b586638eef",
245
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/UploadedFile.php": "a66f1119bd7327a19315456f17ac2d3ecb40e564705d41047a91a02b431efcde1eab2750b2f354fd2f5c10c1ec1b5968e84e758d51210f011dafa8df5fb35c0c",
246
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/Uri.php": "fc5c81c97687dcd34ebd18c6714479eb6b4d1c7d58963bf7f1f732eae98a04b094dd9c99d58f4bff265b2faf0629a456c391ab5b96534c927420f51a95dda637",
247
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/UriNormalizer.php": "8992ef486358f43df4a9567a6a232ad76883d9c7cacdc94707343e5465c857a4385739f66d0024136df94c59e60a5ccbf1850634a55f2cc1f56adddc717434e0",
248
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/UriResolver.php": "46e4c0ed24579ad9a0cf467141fda7dce6dd3a3d3281a1606261f322462d1b19bca413f3c5590b7ad42fda1fc57e60ba86d121b5af0c5b5a2ea21bbdf07f44fa",
249
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/Utils.php": "be75312627f929b2ac94cd6d12972816a13660a40d25cf87f6fc7fb7af416316ba8988656147a16becfa8120ce2a484c84d9f399b43dea2cd3c7ed916f7d8302",
250
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/functions.php": "f31604b89969730b482cd03a13b1356ff9b91324eeaa9ec45a45f86be2bd52a8209cec55aa878d5875a3c82fadd86848d558789d0072e853505d644f0a2603ab",
251
+        "providers\/Plivo\/vendor\/guzzlehttp\/psr7\/src\/functions_include.php": "5b85d1438039f778c454f67bfd3ff2933d06b1aa4bbf9dc516e385bd36cd749f7001de6278c5a1b4e3c5a7d280876d4d35337f87a0dcc6e521ccc20a3ddad1bb",
252
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/AUTHORS.md": "bd202fc574c862a7c3d4a27653605b6fa377823744a793a7848ddaa7001166fd645d6047892d79c8488786d82fee785b87b19e9af1d04512503eb195bd300aad",
253
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/CHANGELOG.md": "ef87f930b797ba0b32dec670491e021b5c881f6986624c1906d8f910e8393b37e6d7f5eb9f860c1bb8447ce61a206bca80db4b2279c57bb064a28be3d83690fd",
254
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/Jenkinsfile": "98d95e7185d040e9aea6e75118ec17ac34e38e17f8ad5a38d869ea02c0c9de5dd79d208a78da23ccb87444df7b7de827b314469027ee7573cc51423521786320",
255
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/LICENSE.txt": "0974968907abaaf61b640ece98a502e3c677b7cf734ccc82cb522b3e166c50eaccb189b4d31b03bdfe8e61a97b3ce06917a7ff5c7c60887e2ae944f909fb6e72",
256
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/README.md": "ddaea1367057ed09023311b6ce37938985c188fbbcb6867c6c3ddfbdb984b954e42fd6450d1e5cfe10374ddc4448f9b96d6130d465983d634ddb3c0b01a276a4",
257
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/ci\/config.yml": "d50e43de2ba68261ae35625f8ce984903baffc3c6535d31a7fb3c5efddd08f71cf0ec3aaf22ee9e17e93852dd99284b653b343a053ba50a45cf6716033131e3f",
258
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/composer.json": "c6b4f35c928d33d62b48139a8be5d85868fdcd0716380865f8dbe0f5a708600ad7dffb3ba510a45bf4a8002f7e1fbefb1c835de7e3e2d9b7c1cbddf9fa2b565d",
259
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Examples\/JWT.php": "ee8052cfd45be4eac77df60902c518a14bf2df07ae7218322493a8e2d115280b87c65f9637ca766a63d82dce36c7c78e894984dc83031a9b7a8d5a6345d38214",
260
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Examples\/Phlo.php": "f9d6482c51987aaa3d7f0db59cd45030e17284262681866999309205161094d96a55a39dd2898d0b7980074d764e1bde6cb6ad1f50be8a40cc9d557431c1bf91",
261
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Examples\/SSML.php": "932a827eedcd81956c275529815a2f7542636b0cb887fcf182648e8f972006f6ba8ea4a763b3de48aac989f26a5e44752c7d3a62df256ee2b6a1c922de677e14",
262
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Authentication\/BasicAuth.php": "42c036c38225556834ad5cb916db0c4783c7127909053ef623e7f71aa51c9fc968b9523fe5dcdaebee769cecdb0c4c76215116cbf5959b268c8792fa96754531",
263
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/BaseClient.php": "029f2be5a3c7734b5030b4fa96e0d7c0c1252bb7b30b9f001a78abaa646d6d3821a127859e5d170ea5e3c7f5c86d06112f28152c5cb2315f94dbccd318f9e5e0",
264
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Exceptions\/PlivoAuthenticationException.php": "7ee7458999adea1ab1722358f669467cb35265eb616ef2eb16e6bc3d42a7f3c2fcb0b42655df8f4f21127bfecded765bcb479a6923dbf1a184e00f6e26321ab4",
265
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Exceptions\/PlivoNotFoundException.php": "bf54dd70534e988c27d5e7d17bf8edf9dc65191b77677d9ffbf95ae3bd019f1ba368065e82440e04f9a0d7045cd62b5915943273b5d8d72ba01676ebf2975edb",
266
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Exceptions\/PlivoRequestException.php": "6655a36e42e700283235b84889088e378bab6861ae98ea99c20bde017ed39b83dc743e5c166e8129b9910a434b119578b23523fdfd5e9e1dcf3d57c5cf9375ef",
267
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Exceptions\/PlivoResponseException.php": "4f18628f90b1c5142446f0e394d5071a91995baec240344a1afa47687ae463cdc3dd18a79008813077a3511c1b00dff7a8715d26990afcb6f9726598c96822f3",
268
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Exceptions\/PlivoRestException.php": "758babb40ea45fb50dafe5231605196214736f014860618af9ca7161157255cdf20c5b0bf534f6f6b30a4f9bf612b5ff5edd2f7adc45553ef12555354f82c15a",
269
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Exceptions\/PlivoServerException.php": "b2b8f6d1d03a720885ce5718b1c80bc75c7f483f72a1d2d2313b98a37e152ca78bb688f7923f025563517a52de7e915325cf86e463a2083c30ca2473446b91c6",
270
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Exceptions\/PlivoValidationException.php": "5faec3f351037d6affa710c10f733c57a7919cb04820f93ef0c19f75b2f2b2b8ae1a0d004c216673977539b713ca31475f233fdd21698a390319364d2b9a4ba3",
271
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Exceptions\/PlivoXMLException.php": "a66429863ac7caad7e0d77f7a1fc105fea0a45e7eecb753e64bfd5a76c89b5eb06e4228bd63a78134090774458a646e10a11417855d3e72b2a6fd75aa754c625",
272
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Http\/PlivoRequest.php": "3fa26ce55e1b201dbe78e4bf3615f8c38d9e6c4e96e5b3673f6cf7985bc4055b88f227677273189381bd29076ae5e8baba6c0cef4bd612f2ff8fbd2847b6c129",
273
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Http\/PlivoResponse.php": "3f9f1ce15ef75db2e028f198d1bb337c37f31fa6dc7e5b985ad589f6a4dd7d873e3dae968b80f5e1eb6056b4bd00e1a4df4d54242206861302f9d6263d177bbe",
274
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/HttpClients\/HttpClientsFactory.php": "a9fbd6c007260fc2169648c9c764ff7b5988af0874b21211f8e85e8a995897d597cbc0c9fce4ec5c8d60a901ea05c5a8cd70684c2302ea17bff528ac674ea578",
275
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/HttpClients\/PlivoGuzzleHttpClient.php": "dc661dc489b30bfa98e0d75f04147d164ad953e7dc51326a20fa94846fe30afff07ce92958c27a9bce9fd15371543852c0be4c24031cf382b54403a0901189ce",
276
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/HttpClients\/PlivoHttpClientInterface.php": "61a18efcb4383bea7598ad9167ffe49a73e295d2ed3229c015f9a5ea08b00362005df1388cf6846f1c331b123b187290a1651341c76ce2cd4233926c927b6e9c",
277
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/MessageClient.php": "f96e09d05b71a2e0b6675300132634f5664026bbb84472a1e7ca5f72b679390170ed5aa0d4e21a4dd1bc646cf0267f0f9240c931657f7cca9b2bdea501586d26",
278
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Account\/Account.php": "22bf526a376e6045fe9045ef4eaef52c769ceb8a7c3ef11902e66acdbb673fa521f70f446e6724155c8499cc700a6cf4f4d435ed06d81baab69f638cb15651ef",
279
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Account\/AccountInterface.php": "5093f51c3803de918f3a500f1754f47a3dbf990008804c07e543da253a22641b96ca2ae5faa7e6800cfa10a41f7d407e5d29e9907c0970a9183a8795be9f7543",
280
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Account\/Address\/Address.php": "7ba3e1e7e136d43989fa0449b29882d78fcea39cb764e54228c7a4a899d5ce4db2deae9d9ff9ed5cc53a8af72f98c55914c10be3dbb7b9a354b8a06e17cce829",
281
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Account\/Address\/AddressInterface.php": "36182073184f67cb024e0c020307d4d74c8b5c65e3ac7affcb76e189c91af9750c318404d8ba3a5a6e104d64459c59c80d7a944395796f0f5aaad18d43d93720",
282
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Application\/Application.php": "9431715557954e8ac1cc340f3f568a6eddd6e00a0ff0356154b2778b118f620d0afad3979e79eef0a583b313256fdd018516cc8128a441dc667b39668b6f506b",
283
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Application\/ApplicationCreateResponse.php": "cb1167e6057eb71e102d55ad2ac3cc2c7aa2a757b317cc97d8d08dc400548d4ac56379653583d53185ee8ab37c4dd189b66af011bc9a32baae55991922c41466",
284
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Application\/ApplicationInterface.php": "77af1063e341dacee15504837264b8140ffa3e8f537b9eb0b102e8f6d184deefab6a08ff7f771965c31d6c84333de9963b2e998bd0389bd0517479d5ee150d3f",
285
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Application\/ApplicationList.php": "0840ebcf3a0d9688cc68a82f11484339d8dadc9d1a50787ee11b3849a361a421f30417ad4322633c53633b4cf58ff7980de6ef87471fc88b16d090f127763450",
286
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Call\/Call.php": "8e0a3bd97abbb7b9d03e22a4eca6eac4989653c43facff064a374f6787698bcc91320352d105f66aa3f31cc0d70902c8cef0f9264062ec4bf4e5cba6d07549ec",
287
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Call\/CallCreateResponse.php": "a3a07958282fc5a6e7b99978427e2361e8828a63c06a940159a7fbb356ab9621a899e6e2a25c27d445fb92ac34b63d8e5a8b6f0782b7f20c7d9f4308306903ee",
288
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Call\/CallInterface.php": "9aa42eadb3b1c06c802d46f1a11b17acf59e0c78ae65b6c9039b4afd9fe53f171cd8023be738a359128afef545a6fddd43bc039d94b014d122e9714f9591ab71",
289
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Call\/CallList.php": "9883c38a74497c496cbf7c4a837051cb6bfa0ed0b9ca9298f8908e7195a000196f7c79b4846417c64af0aeddb6327e45ad4b36352a28e8300c977e21db0fbd0e",
290
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Call\/CallLive.php": "14fc226091078fd069998fe41625d086407e0c22455dde078284f9a3e8fb34fbcac0b75484c5350b437387dc203db7690d9fe1f02aeb09da2d5c57f7b2ffa651",
291
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Call\/CallQueued.php": "64552d83e5911b11202ae4a965bcd7c408643c446566c3d09aebb0bd02fac0dca41477988aae62e91bfb42913900f1eeae9d20693c6bc29651e2734b06cf18da",
292
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Call\/CallRecording.php": "d23438ea994b0ab936c3917d77ae9bb38bc9ca14dff4c5c120a0f583db46891af3bde1a8c3f55d15bacae99723e510184c14c60eb6d3d411d46aa90c5c8acfa8",
293
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/CallFeedback\/CallFeedbackCreateResponse.php": "cff0c47988bfee02787a2d73df6b3165749844c1a93b1fb91e87e80582bd28c8c7efe101fcd532bdab62886eadc6354924eea81278da5037ad9d3ee5d8dc8f29",
294
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/CallFeedback\/CallFeedbackInterface.php": "7860708568f488bd0832e626123f4bb5ab986fa5d54f305d4744503ceb4e919857b78a02b766e7241d324a77d86592f60f26d1ed78955f5550bd0fcc7bbabcab",
295
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Conference\/Conference.php": "8b97d6c9abee836cce410fa1216fdb5aa8a4df0c8543a75c2415bb31a5ee2d87531d5d162b218660a33cdc30539861cb09d85a780feab2d5321d0e8ce06194cc",
296
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Conference\/ConferenceInterface.php": "34f563cac4a75ca234e4517cb4678998461011440f30f9d81895adfdbb2e1960009114773ac30901dfbd2596d327554fd335057de66516b656f7a96446f4b06b",
297
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Conference\/ConferenceMember.php": "1a880200a2988394ed0436702f805ce60762be1774e1d156f38e45be39cc72203fd4f04411a521ceba8fa9647cb00f6d1bc6d94798b66f12175fc68d88c51dcb",
298
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Conference\/ConferenceRecording.php": "1c3239209726556971c2cccc812ce5bb5a3fc8c7a0e4f3ef520e037acde32d9659dea1dc5d3803e1f7cfd39e945a1680983bdeba8cf62459fc168f0df731adab",
299
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Endpoint\/Endpoint.php": "4c9a87fd6042a3eb486af5dc899d1e4c0948de5ebb1467cc85704030947e2588e79d23407ff662a21b097fb46a05925c3df29dd6e2a038555cf44844342cb206",
300
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Endpoint\/EndpointCreateReponse.php": "f77356f3ca29ef7163e47530004a5d79c1da73e922b17333a89512e39c7d3cc842b161d9dcbc745075f6a6c7ae27b7f7cf85f56a6d5bb796b87db4efbb8425ae",
301
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Endpoint\/EndpointInterface.php": "09914bc8e8eeca2812a4dc07469137011eec1dd77b99e3aefc8d5b8f4675b8f221bc54e37417f6c45b07896b84bed953f8c85831f9e7cc7b85b7293142b60fff",
302
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Lookup\/LookupInterface.php": "040b0a2c01ca3c0c02c2c8450b47e8d1847ab7158014ae161ce971e330712d14d389cd746a353707d2bd2667dc604e55c662af8eb15796cfc613f285e170ed15",
303
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Media\/Media.php": "72b83f02669ec7b942dd898a74c22e909cd9b058ea2e903e92ef4dd9e985305311d53c30a0c54a3f0c210433aeb7b8bd04a4b3a768c853aa73ee4dad9c621a56",
304
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Media\/MediaInterface.php": "1cda06754bd1ba503a8405561594f9d3cd5befee2cc6d9cee98542886c71601bd8744899e7ede346df6b90552f05a9eadeec4cb4d11fdab3269de88170cae961",
305
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Message\/Message.php": "54ae356246cc911258552001390f10f701929afa24801b2bc6cde72484c915e2e738a03d04aee90908003efb3b4b3cc8106f92d7ff87d2119e8a350f7aeab54e",
306
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Message\/MessageCreateResponse.php": "75495f459ecf577e2e0c2f8c075d569f36df80c5c828fd1d6b84a001de2c3d032add50b5ef08177d5c68014fccbc939c8ff89ce6c884ac0c1b64f4301d81cc5e",
307
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Message\/MessageInterface.php": "e96af121fd4a851e4c1f27297c602a5e6862e0ac54974aedb19248f017f2d98386ea9b495ef6cb775aacafa7b51b6117665c803356442786142c15e86066ef41",
308
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Message\/MessageList.php": "baacdb72ec116be9a14b8e7e55d6c40cfd8b04c5bd1b0d93d5c9919ccba2591105e03dee96effee29e95ab7b7e58e45569760ae825351c1891877dd96853254e",
309
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Number\/Number.php": "1bf8e1b1844ccced8d8068a80ae45b6904f59b0fa0e7d6a7c5b43adda906859ec11d709a501f560aac3f8315176e9260ba4796aa9cbbd637431ec94f0ec0c668",
310
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Number\/NumberInterface.php": "e633bf2e705735759f6e27f9e747e3e05e839484b57672e2da405b7e2d8615653fa828f8295a442d13f5b64645fd009ba6cd923f0c163f2070710c7df57a1a70",
311
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/PHLO\/ConferenceBridge\/ConferenceBridge.php": "3da97309ccefdb15596bab5180d386e2a78cf938823225820f5b206d8d8f366209dcf96bd139cd0364729c8b733612ae067d03e1e29aef472c4dc82527d3002f",
312
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/PHLO\/ConferenceBridge\/ConferenceBridgeMember.php": "9ee728dc1f37fc183fd4890ca5d213bb1f47899d2379a16009de7ae32b75b459444a1a329357faff349909ee89843ac5798c75699fb2b8d939501f61dc09b564",
313
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/PHLO\/MultiiPartyCall\/MultiPartyCall.php": "d13d863ee416714a697600882f33b88a8bc9de8d5603149fa199f787d7d904d55aaa6646cfdb3d71caa99e4e95d7e352199e8b54230d3c64cfb81924f1b603f9",
314
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/PHLO\/MultiiPartyCall\/MultiPartyCallMember.php": "6e8f1c6a1177d0c933352bc2d8bd54c989db7679f2feb893f430e9e634c446d033d01a82ea740185b1926734f285facdb3d99b18ffcefe83be723fc08b50fc12",
315
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/PHLO\/Node\/NodeClass.php": "b8a08dfe16a42c08ea66d141b3b4471caffd2bbf89fa4b360a1b16a7072ea29d538792c16b93f1e3f1a1a01d564acf1a40906c32482c4cef0ef42f1647e483d8",
316
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/PHLO\/Node\/NodeMember.php": "e13f76753f278f07e8778f1d0ad64c9ff401633423ab2476700ad0711ea5534f7caa871b5e10fbb26096feca64471205082f9ba45de607e7ce71eccda0e7db91",
317
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/PHLO\/Phlo.php": "da8e7b69e9290d876b6ebe6778c09ab68f47f13cb22438ac92d6eb880b7fe72ffcc68c681cbb9be074e36f3ce4afefc69680e7a3493d3046a04ca9ec432d7a99",
318
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/PHLO\/PhloRestClient.php": "5f3b9bb5e3f7dd96572f1dc71531caeb0b14b21ba7c291561c1ebb040c3ded22bfc0dbd9030843cfeda8b4f83e69d86ed9db2b3b7d0cc8b311ec64000f3b935c",
319
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/PHLO\/Phlorunner.php": "c1f3764aa4a4c14a33614bc7cdaa05043d268b24f88cb2312bec3596e5e7e5286e9d0429edb8583b640723784b28ebf69df691d5e4ec53b7d7912252832c3ed9",
320
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/PhoneNumber\/PhoneNumber.php": "57bb602a9f511dd39c7143c50a9ca6537bd83f398eeb6f198feec689877a9a423d9cfb0645c4d20eaf30490ae6b6ebb91fbf1d00ce633a2007333ddd6273b032",
321
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/PhoneNumber\/PhoneNumberBuyResponse.php": "6929f9a7447425d76afae60b91de8d6a5a42a1e7864871dc73a40199181d5af8be9f645185ce1e796e75440d138cd0f69ef86ef404879d74b58107ce32824b6b",
322
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/PhoneNumber\/PhoneNumberInterface.php": "3720a8056618a019c64de2e4e05e99e0b30cf48de07117e75172b8ba02f2b2c60a1e0b12c3cc07b3f5ba8aeee2e747c3eed43b5bf589c29c7236b47b5ce75747",
323
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Powerpack\/Numberpool.php": "a774de315b1d34a61c9b9af9b21b8fd1f624b48bcdbc7ed1302ed25cc21093e05ce1533c0ce4788ad36ab28792878321a99b941cf9e1a8ec7fa2f2ab1d16f872",
324
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Powerpack\/Numbers.php": "f62f6534b223fa353f2363e38fb1069c3d10544a4cae2efeaff30019c0cfec7de2b4b9f551cfc16bf26fa1dfb916f6d916f9cd1d1357f8cf6f7cc84815812237",
325
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Powerpack\/Powerpack.php": "895da995fc1445bb6f7458c3904c918d8ba8e8db75e94e558f04ab8355058bf82d881d7c282fd8e03acf723c232f3081733a9ace2bef1da42c3e9f4de452d2cb",
326
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Powerpack\/PowerpackInterface.php": "e09a8e4e67ece27935a81730b7587bf29afe72ff9aac57b6c0efa6fdbc4b7cf4c91d60bdcc506a2c0b86f7a4cf7df70c38135e295504417d39024a4671b3cd33",
327
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Powerpack\/Shortcode.php": "afd1a0a277918a55fabfc2b46460ab6a8740ac68e1d7b9a0180d88229d7a93269305765fdc362c02cc2996ff7c3d8c95417bc90bb74e44f9c2cf12f023f45b08",
328
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Powerpack\/Tollfree.php": "0c63aaf33046375a8d7c0f9c7c092ca1041f553b1987ad5e2944630dd23f865785e06205b0711c215468630455d8c2264c0b141fee5cbdb4bf9430e6ef90527d",
329
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Pricing\/Inbound.php": "285fd073a2fbf84c533af3c0e60b369689592882364413a1879691a025655bf4bdc40831d13d96c59ec7a8827233e92d478c14d1d648df885c75fbe3d054351b",
330
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Pricing\/Local.php": "5140df58e671179a4edbfa82fcb7b7277e440706406200255ade35177e9a715c3340f5920c4a57c351b6e222f7bb1ef20b207d0830c487bd14b9fa713d3d8c4f",
331
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Pricing\/Message.php": "ae4e8bbe3a668748ba57bfa571cabcd97932d6cb7a8a63ea04689863ccf75a63e0aa867fad60c39e263cc685521a8465b46f730014933dcdc941ebf152fc437b",
332
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Pricing\/Outbound.php": "7656989e6b1da4e4887f8443304e422ad2aa01c9c05aea5b5245b4f3edc333935be4f573fc5105e13cf03ba6ed0ee0ea323cc76c833846bc5cfa01f3a0f33763",
333
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Pricing\/OutboundNetwork.php": "900ae54c0c0aa0f85af4f02da252a34907999bcd311e9e39ef8d8e27a16fc6c8bbde5d5f6460af6b8e68cf584419ccd7fbc4de177cb827cabb5ae9b2c896494e",
334
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Pricing\/PhoneNumbers.php": "cb51001dfd504ac52dfd39e2a0fcd01686de42e78464c76767f99fbc7884cc2d6e304cedd72e66dde42852f72cd833dc49dc1e92fe1487b2682648432e7979fa",
335
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Pricing\/Pricing.php": "5d197bd5eef109ba3d877f6de48f8567f135466adf1d811d32908d8d4fa7c8961592733d6bdbaa4f646c3d25a31c8098768dff183d192617b2c1726e8f41c447",
336
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Pricing\/PricingInterface.php": "dc940fc2f0338348b06fefb22caa65b98fbfd37063621fb4e4f1e23c5dfe21149e2e648c1a32b09012b34c5bd622fe28126bd33ba1255c6ae3c370dabce6ee97",
337
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Pricing\/Tollfree.php": "ad733c0d904ecfd646e79a3b6bb3ade270f99df5e6353bd6c8695322a71238fae107a55d33167063dc2e4b1b905273bb0631f051d06cbfcf5d01c94e9252fbdb",
338
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Pricing\/Voice.php": "ab645548152bfd840951e981c0d18aad23d613afefd4453af077a6055f902d6bea6a0bcc805288f130da6686d8419913e86422cae35b57c1087eea3371b7e799",
339
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Recording\/Recording.php": "def8da050e24afea59514b4fda360ecd1d80a49df2013b258e3d78304d6eb2ccbe21ff1ac50a851079234a1460d0f2750da8fb59c9ff184e8ba1f1becdfffe6c",
340
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Recording\/RecordingInterface.php": "1953832ff8be0a6801f306632f3ca3bc46f067d08662b8ca6d53e29d53507a48750bdd891d2d0164c029f675b8c4c1dfa6765c9abf328578838b428dcea22615",
341
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/Resource.php": "b8a8f583217c43c3eceedcb8f047efa1569bfe5f440fcf4f252f1a8402f484e18abff63229521f89697c1f7df21a2ff919488fcd9df42b5aaf7a160a50f0c62a",
342
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/ResourceInterface.php": "85bde5b0479b85aefa79139d36192ac334e3deb3a07353b7b1b0cea1180a050a92dcb563ef4a968b6436f60ac990fc5c1322ba3ee6f4ffd41d2997d604653b6b",
343
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/ResourceList.php": "71fc010407c57d77f5b31105f6e645d04347d961c3c81eef6cacc7b8dd475d86bd228c5ea5dd5976ce34d025b0753083b5361a47cde5d5daf0507678762106fe",
344
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/ResponseDelete.php": "3acf13bc2797c0ed58c78abac46ae2822a67b9c9194b3c9864738516847618c0033fe12c5a62d9dcb7d110ffd4264c534fded370d04a2960a2da32059fecaa8e",
345
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/ResponseUpdate.php": "4db3ee43405d0a456dbc23801c2c0d71676c3f88ac7c4161395ad275e7fd0dc6b53aee99a882706da4f14fc6c35844d54143a7fa3b6597a5a25d59ed67e0e6bc",
346
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/SubAccount\/SubAccount.php": "b39e628ab06827320f3dcb47d3ea55d459af1a133430e8e51e8e6aed5216c31b54498c836cfd2a5c5f2d9cda4bcac03ac476bd8ae81c3ee2c7865ddfcd359dfb",
347
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/SubAccount\/SubAccountCreateResponse.php": "3b92a7ef8da848a7a5d7b79436ae557657e97141ecb2bad076e69d495d78f94f6e9c68464dd7e790d64dc563428e4567a1baf96df1f8bc97cfdcb946e60e94ce",
348
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/SubAccount\/SubAccountInterface.php": "a4cec509ce127faf30261cf75555a2905c6e551223b4b90949251f0822dc20d7b97efadbcb6bb189cc9302acffed8106ceab79628a7531c161f4f713d6a26c4e",
349
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Resources\/SubAccount\/SubAccountList.php": "228e0fc0fc27fb523c9d2d9e62de77a5deb3bb2a29c10d91d7c59b6cf36b3e12b8b1935a69fb0ceda72c4008b2a04436e6aa3f84740edf265d0f647eed7c52d4",
350
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/RestClient.php": "91f01799f98c6d65e1a0a8025668fb0c9f5fa4b77d44e86790b34599c2b9045cbce2cb3a5dcd93a1fa8523cb688d9f2b895d7d5f2377f64f2e33ce68e621dd82",
351
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Util\/ArrayOperations.php": "04a84eb09d1ba33c3414dfc74d1c4b31c3149dc8e3a038912be632673a92e693da8e531a987c5ce747aa11fe01bf65bc05ac91924ccbb8f157c15c62f8ce9694",
352
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Util\/jwt.php": "61ef00cfe10afee4047149729431595a9e21d44b25de3e8808014312a869110bc22898552fd9216cda6906c91de2b3ef9d723ff0d4e18020d1b7f5d1050fe810",
353
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Util\/signatureValidation.php": "2bf40afd282bd8711459cff1b366510ea253508349adca2f64ad101b6c4e3e20bf405194b9e421ea7cad5b738716624127969de5497e16e3647872e0b3bfc6a6",
354
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Util\/v3SignatureValidation.php": "d70083f5ecd20fc41035462a2a27e04a9367d9b7b13e6bad5579dde4556ff187b8ecdfa17b2c07a0fcf88cce0141baf7dccfaad85a17aa2fd1a7afe7998d1037",
355
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/Version.php": "365ed59af02f30183af840aafe55b67b682919cbb3d662f860baf1defaede8a67fccc5a7f087209494239466f356fc83f612faa02f9f03a301f5ffc66b52bd09",
356
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/Break.php": "89a669d486a72465efc2c6128deb6760dd86c9fb69cd8c0f57c209d10eb74067efb50bc6f0e68e2d1c9c2f39862ef3fa03a35c65b7395aea6ca963a013869658",
357
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/Conference.php": "bf673327e263996b05a0b45e323168e3d44b27a65efb8a8acb0eccb0276360c1a0391f08edc34ac617aa079c6c2b1f45eba6142446a7ae2286e23f337819caef",
358
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/Cont.php": "45ed9435166f1b72dc5ee98afaf3547ae646d16d41677ce5409a6005ccb9ff23743e4c528385a1e0a8f5570eb7ec9374433f609bb8cdcbdfe756842f1005c52f",
359
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/DTMF.php": "14c619e3f01d6dee2dbbe9b718c6c64458a97bf70ae333455aa45c9cce91e4bab693f5265de0099c9cef2334a5310bb85e3374c5f0cde9b93c3051cdf5b57a4f",
360
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/Dial.php": "5370d1f1a1ca8420560fa204d295558ba9aeb626fb7149ee06e12acf7f4b7d079307f329f91594e138847a2b3dd9e3f3e9a9e6e774a3c1095c3201ab249e9c03",
361
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/Element.php": "4913c3c78365a85eb5c90aa721b0e1cf535c00d5815f509e336ce635cf47a9d9aed1346ff0cbc875eabae65190be2875d0820312a6a5c90c6df3acfa23bc80c0",
362
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/Emphasis.php": "d6fda7993f909d3a1a50441ef74003811252d68a33ec2da63d3551236a005952d3b6c7e2bcdf5d9c85d33bee2a9255dbc2b95988cbe0e115b42eeb667d58ca38",
363
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/GetDigits.php": "e41a4e05fd55fec82a24cb2a545db122000251abc0986715a4d5866dc64604ac340c59cf0a30a35ffeeaf17713eed730a7705f32aa20aa3b14ffea368cdddfe2",
364
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/GetInput.php": "cb11a5e0311d3b8938f7d94462d24c5d4b8a2ea4d733943253ffcf36aaa648cd3a4337d732799f382526e0e2b2059dd1489e9ac7fc5ae478eb1db07b3830a711",
365
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/Hangup.php": "6a7ac35846ffaf61d8de286929bdce05974799b26b17f4d61e68b6f740cff49bc4a0b72899d1150ae03d72e4f8c4dc7cac491872e76be0aec6b1a665446a9226",
366
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/Lang.php": "c16c3db519373df61712fb1748f91785d79ba0fcd7e85a32cff1d17ae89768cbc10b3c4cbceab380fa9762cc1b6948d8fa56054d78185f8c9c1d6c60a012f527",
367
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/Message.php": "541a76d5dc1e25633d7bf67c83d1fa123820296b4755e7e48aca094040ba0c2acc6215eb29176551516941b8e8225e6084fbf89892893557e12f678cbe2abb86",
368
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/Number.php": "82569de717d895eca9c4270a3fc48022e666e59e6d6c74dffe4982a8db1f6031d80c51863226c750cef5db111f0de940878baaafb352153bd0d053f716c43fe2",
369
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/P.php": "d8bc0f70c13af91549bf4c37ce4c95b6683590ac9c9a3006bf2a4dc02d85ea63a33d0d8fce4a6465f25e0f86b35994d98e7bf75c07e30737305a7f2707ceb444",
370
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/Phoneme.php": "9bce52123dcc7451f21ecb2e155884479b7530715d78d175cd616da86198151481632af22cfc19f9c70a4cf0f29f3262f335982fc9988e4aa3a435cd74f14c59",
371
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/Play.php": "9b25a9f3a6149ad856c4aa008c405192bf2804432d83d3a572cf066dbb151b8298272b0a9185bb26a5faa51c03d069aed172ddb135d4dff3fb99af9fe982ded5",
372
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/PlivoXML.php": "03c37815022f4b4e7ea917f69b5516c3bb5499e68b65ed1b50f7427d9827de1e84037745d25b420c1f81ab829f51ae752b126943005c82b06a668c8ff895e923",
373
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/PreAnswer.php": "f66f22bedaae6dce341d650d5ded5007d867361c570162a642e0a15f5fd6e90b49a4c8fac2d3a1cb5fea446c75e30834a1106a3acd1ac02a87b5a7df7c1d5af2",
374
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/Prosody.php": "12c8b634b226bad4ec0a7dea7b8249959943bc5ab0e71f75fd42afbf6d1413834563c38430e9348bde2cdf1059f266a2ef59fb7a8f6187ecec135ee9d5dede4b",
375
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/Record.php": "070470af5650220e0556baa6b109684e1abceb6e80af620ec750f0c691824249121e1c6aef6cc1c91bebb45b76ea9db24f9cadbdbab8857b367ba2521d1cd001",
376
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/Redirect.php": "34e09e0b208c4dde1c4b53c451b09f23985c8f74737e73f4675053494cfc81b14920afd6620ff161877c4e1b7b6e7381cf3f824a2b06508d84299aa4e0e45690",
377
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/Response.php": "8db3a9e823e3c11b8377829c783d93f0b7cf98afc6d837e514803b478a7887d6602bae6efac9dae6a2e7683d8409c23f78c463185754fd7916845aec23e42c58",
378
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/S.php": "d0dc3f3bcc818d107fd8e4be38718587edf610e3f840d7e6763ce8fef51a1e96de3b49076995802aac9edc7d8a976ef024a1d45ef634599a56d13c56a8ba73de",
379
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/SayAs.php": "46c8fff6a9dbb36df1bb14d0c4247569e00ce77b37730d7f8fe6fc4a404a632ae70e48c774f40c4ac0e19b10ecca7c09686c7d5a6fc7d5311edcba657177b6db",
380
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/Speak.php": "d18aafc18ac404a85d18627ddc66d2810ba1061f8e0d3d3634d5f5258b239a139649a8cf479367dc026929010288a291aa1144aec2415a2de6083040b8a4a96f",
381
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/Sub.php": "9d34d26e76074e65fc01a3a477ac176027b1ceb5dca2fff450111bd2cfc0027c7f7338777b494728ae2617a27075888ea699d4226b60049c4fec633d42cff8d5",
382
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/User.php": "2dab0ac6bb38d9216c1b39b81ce20f1a2af1d385c90ea13aa566176eeb288f8ce80e11048209abf8c38151207137cc86b754b7784cc478dcfa1f567fcf929520",
383
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/W.php": "798d6f10e6d07a54b29916216dbb2382f25bbf2f96e15906f842cd2ae4aee22b8f3e56535264b1da6d40835d5b9da6a9f4346303f7602c9562587b29fa419f3b",
384
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/src\/Plivo\/XML\/Wait.php": "99e6e66fb4d2a81f0419ac823be64ea8c81e6ffc8313934b41d6189519d053b54b5e95dbc7b869dc979b72b551b5654dcd6eef0540c3b01eb900716e97d52dd9",
385
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/BaseTestCase.php": "662140921fab3f1e7be65bef2d063673900eb3c41de8ddf68320de194e254ec3fbba3322790812c258698af81da35277cbdfc0d2fc957fd5f68956e7db2ceac2",
386
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/accountGetResponse.json": "1ee7d7e260e8678fa70fa47206ac7c4645e9d698da7017ab05fb56266710e34bce48b19d3c65541a084be28cfe918e81fd52073064071daba77355af2eddbbf2",
387
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/accountModifyResponse.json": "ef0e777d38b4605ab58d951f26e975566b61a26ebe5710b9c8c7588aae799c68cf76dc5860f44aaa666864f3fc1f74185b5eba888c1dfa8c2004fb8baf6d859a",
388
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/applicationCreateResponse.json": "19336630707d50a021e3dd3cbcd8a229f9f6123211e27fdba211494bc40e9b9fc5573ef328806bf00b937106e7c894ef96a98080f6003d91cdec67f50196849d",
389
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/applicationGetResponse.json": "26a3aee28fa9219455b0c7a54d47eaf1ee7e9fb526185d1598d5611246c1ad7b0cb1abb05b12d21189463955e25d2da906cf5b04f1bd4c3b826d44de47c0d56d",
390
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/applicationListResponse.json": "b363791ef3276030677b53f555a42deb02a9873cb5b21e17aee9176d425ed38c562da7fc162cf5771f0bd259b46d615ded3799f34f6fef590e2df97180ebd228",
391
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/applicationModifyResponse.json": "742b49b7f428a281b1189fd5f23811931f2d6c71fa271ead086b6acfac63bafed22b86f2e460fcea35d8bdd46786c5db83707f35c7a855efbb92e51ec01a4859",
392
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/break.xml": "6707a46a4316a9f23104a23e4ce9c79f8b4f969639c08f5196a9aa94ba3abd4a1972a29d6131e563a685732e8cb0a4fc90a76f2d0ff5b72637fba2f974abecd3",
393
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/callCreateResponse.json": "513446e1e7fb97b30b86dad2119bc9fe73e70f01f4976ac40e57e41e7d96a2faf978fc72fe2ff49e3326fdef8e17cb4da24bf665be81089aad1232716e42e114",
394
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/callGetResponse.json": "2958c05e7fe02f5f6f2f8834b34050599df05c6f5751fde2fb038853383683e78b2b33b9534bf8da38770173e08ea9c7015d7b2d4f270efddcaedffd77ce661a",
395
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/callListResponse.json": "b2b35a27aaff76dafc6f5a42b6ff515e56ea9d7c196670613b97c2b4c0b7f2dfc3ba7ca705b2618f3851e1db554268018c7c2bb658e94b66493576048c54ab49",
396
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/callUpdateResponse.json": "06be7ca7ccaf82f24f23e8c33382d372ba639662283023a9b6ef555fa24d273efd845ab27fd423dd4267d66a8df24604f96113aa3bb8f8dcfa49e713f3d71bbf",
397
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/conferenceDeleteAllResponse.json": "6722c7663c8877f4bd5d417638d5a0fde3db7cd2ba1880dc66a7ce9ad25a14de60b4942d84647cc21c0b12211227161349109162ef3eafc2a9607c2645d3c93a",
398
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/conferenceDeleteResponse.json": "9a8baf62bab7971a89490d637633a3d498d4442bb11ca29486d21a3dde432ca6c0cb36d236bbc94859efac83b2e56d33442a13a4395f4b026dfece2103ca790d",
399
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/conferenceGetResponse.json": "950fb7d6e6e120ce670da43937ab4ce9e7a7df5296848cb52261f5f854bd89d47f26d76f89929adc59bdadbc8d0e77de79f29edc5d6e6b4b73aff1a0c126bd43",
400
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/conferenceListResponse.json": "9f5635d9e0988b03c2bffa8457962cb6870a39d4354ec6c065b58949850b188d2829fcd3db1761ec42a4bed30ee3704b6c353d2b9372742cd6d8b00bff273dc3",
401
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/conferenceMemberDeafCreateResponse.json": "b39ae8d7a1de7d5732afdc00da955a91850b855f6463b143b5837023dd8281b450fa79635a3fc729b5b198c6af5cb57f9c6797c8eb56daf72b7c7131196fb4da",
402
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/conferenceMemberDeleteResponse.json": "ec18404f82674de8b7ca25eaf95074cefef51b13b038de14dc9ed5f2664c6e6c5c87d3f7a08eeab3926869e171ac26d1647ba1cca03253085a194cb0fbe16975",
403
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/conferenceMemberKickCreateResponse.json": "9f924beac462c4ad9f42a705f7bfde5aafe5e73563b07e98ac9db42e95d3c657f5c4ba0d6ea64b01e2e061563fec41d53f8ae8fbd7f5e08857a903c948019e1c",
404
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/conferenceMemberMuteCreateResponse.json": "c3f1c38b6c8295b28d531c446199454fd7422d00e3cf71fdd318a821edca4afba444f8cea38175c0853b34dcda5dcc2c6317a9f3103e16474fb36c43241a52de",
405
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/conferenceMemberPlayCreateResponse.json": "ac345d15512ca5debe0a20092d8a4bba1f725a581799a632bbdccea771f1b6094b6df3362120a29c1d9109cd8ca8857447c3be08436fa94a5a4304725b75ef4d",
406
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/conferenceMemberPlayDeleteResponse.json": "10b6ab89ba98b9d6d08dba8637971ca9260757c318a4842521c7d2bb2a1b967498453aee4cef6fd964cf2e614c25364f543412a0a88b877154b3faa9f18ab3ca",
407
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/conferenceMemberSpeakCreateResponse.json": "b2b01526d4838a72c816ad9c6ca7f9cb473a89818d4444b48aefc269d0173fc9eeed1e2473667517280c18315d67a548f41937ab4b7d26f2edd4d0e13486aff7",
408
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/conferenceMemberSpeakDeleteResponse.json": "d42658e98680911d21be32033be208b53071e3ee2c514a86809ef4d06cc138ca0a74d9b2e546c54b51c66f3aa891cf0ba3b4db9a6a07e7f06ed37bfb39ef3a6f",
409
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/conferenceRecordCreateResponse.json": "c9d8570ab20fea79181b1416cdc44b8e9f8b18b06ad446a0929ecbec53a6bb3d66ddc8609a2baff92d8ddf9bb68b802ac4eb3d62e958d2cdc1485711a6286ed8",
410
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/contSpeak.xml": "1115d194144f96d3b4ba895d45268e346e7e56bd308b4b7c58bf62712380908bb71d5250323bfa6d13b8d25e64a86580437f7ac1f2c63896965e3c13909c240d",
411
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/defaultSpeak.xml": "2449ff96f102465168a4551ddac6ff85bc680370b423d46ee10b345c128755560e0bf48c070081e8045839503450c0f8b443fe0b33b455410ad5dfd639a6adb0",
412
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/emphasisSpeak.xml": "1ae7422578c6921013c5dd65650f0c1efa50512824b429334cc150ee6872dd2a7981a125b07a8023e360d8a881a32333de24f1b595c95a339507dfb29732af83",
413
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/endpointCreateResponse.json": "e0cd43507839270c51117e48fdf3158e67662c1bdf9c8c964b57a13c15517ab7c83483855764b763f63bfee011bb893c20eca7e7a0b3b8872bbb1f26228ed720",
414
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/endpointGetResponse.json": "05359131cc3ed432c1b29f3766d019be556f58e5e7f7b502d866d0057c04917ad7011bea5afd7ca8f2814dc75c45a52930d48464f7fd740ae94b45d0a07d3627",
415
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/endpointListResponse.json": "d6488ec5e6277af9a34629d901a211e37c9a522107f84ea77f861c417345ddfa409d7de389ae69b719997600a0495289bcde64791ef07c257f75bdef4fa8006e",
416
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/endpointUpdateResponse.json": "3f20870d3ef78c57407bd42cd424775a7014473d891020bfc41fd78c9187acc3d7fc2a2d7a137eb5bf9e8741525db9aec853889b11d2d3ff508f7fb16a4bfc88",
417
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/langSpeak.xml": "1eb16f6028ee00a12e677560ec9b3ca4921deb2d6da15b3686c43f506e9a13ab0cf811d71e942e1f225989f3a486ee39b4949d17d8692ac0a50574845491cc8f",
418
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/liveCallDtmfCreateResponse.json": "f30ceb762f24445068ff4a688935a84cb64840310bd518806c1259ec26fd60da6a8be9f11c9c0882d08c857058944cf1c69c95035517716dba322a1a865435f2",
419
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/liveCallGetResponse.json": "339633aa5d9cd2aea4a86dc48dd8c63ea8c0c56d5cc0f4513bcd2d66df425ce4b74b246a8c39d6cb0dcde75a8c01d4ec8347e69342649ac27599a79a72fafd9e",
420
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/liveCallListGetResponse.json": "7e8efa8df76422d6a9bb0133c81d96b9ed932f7f529644a109b35e9f8f301b3a548e8e7f6a9213e301f25e914b98c3855160ca7e0d6f0283e947cd6fc95c5ed8",
421
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/liveCallPlayCreateResponse.json": "4cf2ddd4f3087fdcdf772219c5ed84ffe1dc027208540059bc532961b6c4cad382bce98dec481e0245c99e288c9523e8f33ae7c3c35316c8130f49f81db40604",
422
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/liveCallRecordCreateResponse.json": "02f2c4c88fc63e5585f6e5988d5f615488507a7d7eba442430753a60f0cc2763c38abf905042c9ae0f7d017dc50caf67f269267972b5a7fdd4fe7675572589a6",
423
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/liveCallSpeakCreateResponse.json": "ef69736cd0199704894c2fd938e4f84768b09a6b9d2f334ef0a83b1750db0bf0eab538471fead4397b49ffa8e86011da111e867d5d8b3532bf3f4250958d6146",
424
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/liveCallSpeakDeleteResponse.json": "63a9fda757cfbe1a338c42f19532609e8607f3c2c8a317ec8e5aa2a164b0e9f9a652129bbf7fbf9fe05c38a0f68138ba10b4d256f48dda1fa292c18f2b717d3b",
425
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/lookupGetResponse.json": "6b2dd461ce651012160ed88d092de0859ff1cc132c57091a1064b5745b83cd6e5144e8204b6810da7bb675eca802fff54fa298f03be6ef858c59058acd24e640",
426
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/mediaGetResponse.json": "251c9d7226411a160031776b1c7039d7e7f3d715ad7bb89131353611a2509a570656b8e29577e505102cf588ba50cab34b3b74351dd33e2a99333676d48b7aaf",
427
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/mediaListResponse.json": "1512baf046701056ae6b5ef06a1e6405cd62a27d4b82f5b38ed2b2ef6faddfd147b6d57074d04d77cc14325d50d7908c0446acd4a5a0355e9dd9316f80b0f448",
428
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/mediaResponse.json": "329e01ec90033528ca170704dc7a3de8f5d004a609fda5abaee4ad610b1559464a97b423ca27248f49fa3696f12ce6c1b3ef69ba198ae57877927ff78257231f",
429
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/messageGetResponse.json": "10494dc350e9a659083f44802a899a893e67fd82acdc506210c827642e27bb4ca1fca7c00a73a7aa20900ead392b9983ae719c6a9aaeeb0ff9f9b9e02539ca4b",
430
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/messageListResponse.json": "5751782fdb135ac45cec47687b7bcb10d4e2c4c8ae88461baca0eb6f0f81b8144aca9b610cc6ef7f3cffd4b5dc2ddac08247e74608166d147bafb1a9ecd4b834",
431
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/messageSendResponse.json": "ae5ef8b7e2a5db03fc5c04e96cef35b3f819f1670cce72e0e729b57de018bd6ffc254e00f20fa7c662eea100f78bb1824f0080275ac270f7e1229566683fc62a",
432
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/mmsmediaListResponse.json": "fa4d1e3885b6c84d72c9f9a4a414de7d1ae1d574db325cd773600c7a17f83fcbe2a84c0daa8fc690d5f5d95431b1ffe5097c17279593ccb4155d5f99b1a853c6",
433
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/numberCreateResponse.json": "e7acbc2aac3a716dd50e27de2e8937e27fe70da7dfcce17561f4d81a2de53e8cdfb5a695255e1ac65c8c49e4b894722e7ecc9297b9d040dadff97d1cb61ea414",
434
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/numberGetResponse.json": "261a85df87eb4ebd1d310575e8f33d94f74c30f5ba3aef1ed47654f7569ebe4310019c5dd317a8c6e2b015a1ac3f72455118e0878d688817580b18b747d6dda4",
435
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/numberListResponse.json": "134543e58c07917a79e0498e85466b9cbb1c97a0e3087473463419bc6c178bc278ca75e148f885eead7f6b1074063256fa61745c57a0dec4ac060c4b03afc499",
436
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/numberUpdateResponse.json": "e7acbc2aac3a716dd50e27de2e8937e27fe70da7dfcce17561f4d81a2de53e8cdfb5a695255e1ac65c8c49e4b894722e7ecc9297b9d040dadff97d1cb61ea414",
437
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/numberpoolListResponse.json": "961fe25a8fe8c35dee1b0608a24d741b6ab91f2104a9f2af2080279d6cbe4e631416d7b3d8e3772715e376a603cb740d652435a0f2d7971e64e00eb44e7cd518",
438
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/numberpoolResponse.json": "c725314dd96d000028683c175528d15657c046cb421add91a927472c235ae5c1ee1aab060aa0eec56b6c717138623684f827a2de50bdbec1017e7bff937b437f",
439
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/pSpeak.xml": "1e49af0752b825db21fc50126642fde3f39dd8b63cec3db00c3df92ca38935d58b8752ad14928278b98ef23421d0926d624b6aae948f9473398d25e2d087b963",
440
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/paramBreak.xml": "1202da39615a87758a5fd85096a4d98f6c2726d705ef0b1086cfc66cd0f456b15e3f79d9850e1bb8b99e9114e41b3ca19ee4fd269a42c002c205de005c72ceef",
441
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/phoneNumberCreateResponse.json": "a1dd38958ee69b5036aaa1c86cc730802dc2d7612eb1de9266f9a6651f6f067cf9a42d44c736bf85d1f40048f01f99fa05ccb3fb26baf3875e3bea98fbb9bbd8",
442
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/phoneNumberListResponse.json": "f2c263fdf122dfcf98289f6cd9276cd8c22fe4ff5bffca19b3509800d07909664e9ddfa3e145da04c06dfc6c5227a39868d17ca947e55b65a9cb18a6faadfe57",
443
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/phonemeSpeak.xml": "30620187252e4a92154e06e611a2cda1ca881a0d85b1c6c36e3c713734c0be9ce79bb9ad38a11e040cff437c5676c01638eecbacc5b50a20e0adb506565a9475",
444
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/powerpackDeleteResponse.json": "f170bba1b0b6bb42c88bc74353ea4db09b82f07f5a2166f693d0579e5b7d6beacb8cf11e39cff546345333b14752456212584e284c2c360cc673d009fd2aa018",
445
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/powerpackListResponse.json": "0cf4f36945bf4f73377a6688f99bb3efb0c35924ca9278bd777ecd0081c3f667d45de4a34f7101588b7a7b3b20179d18a393dcc468ed88df8eb53b5e2463d7c1",
446
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/powerpackResponse.json": "4318b75a2ac1642f6ee33fc62f18765a5142aa52e0353082a9d38cbc7660e40f24e1665a59c723ba90ba9a86edb4cd4a396bb9a0c00cebf6d5944e0ba84e7919",
447
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/pricingGetResponse.json": "25a616f338c147cb22228535abafa9c1439f663230d1fc5109af24f4f11a637c5d0cfdbfbf3b2762b87d0b4693f14223254e431f3b8ab1f518b32ea884e2d1fd",
448
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/prosodySpeak.xml": "0529a04b9ebbfc245e7d50bce1177e3eea9f0f6ede900e9fd3a447f86078ca86fe8c9911fad4645494cc784394194c5e6b63141a2a9125a1ecdde2cbe8bd7c86",
449
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/recordingGetResponse.json": "bdf9cd97b6c687685b9c37a0921bcba910dfc811abe416be7b17fefbf857c3ee1233e987570eb444d168edd660c26acb55377f60b8aa0a898f0c9af1743edc81",
450
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/recordingListResponse.json": "2d831eb418cd0de8a0d63da8a2ed133005a3e15e4e021c3451a737c45f42e5753ca5143204acf2f8bdf6ee91cf1ee8b04ee960f942ae0e62bfc3583ab44a1dbb",
451
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/sSpeak.xml": "b81f50357fb60ad968d8e949aed15c7544abed0a45c26c5bdcd4b166fa1d9bf74f57137fcfd378fec345e1fb2281ac38c30b2a3150cc6fcdc13581ea29379796",
452
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/sayAsSpeak.xml": "84e2d4a310c8d1fccc5be4be4cab026e1dde129ed2e18ab4fedcd50512cee91a52cf437606cc936c474cbfa508a105f36272edb6bcae29388f2a75bcb354de6b",
453
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/shortcodeListResponse.json": "449e0c165ad81254715b4521e5f4d39b0a6d1ecd583bf337e8b85ba40550a0942c04a8e33b69e5327a275fca4e42e31dd1719f100c8d6e459939a3696ede1a71",
454
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/shortcodeResponse.json": "867e2309b5c912c9dac5b06929a835b578b0dd3391c43f6e0d454adccf997060e1e5013051b394a94d44af3e5cfea67a88f4376088a376a031d6fde5fafa09be",
455
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/speak.xml": "a781afeb86ed31833e74d834de6d9834783264ec43678fe3e70a7f963e97a9dfd05dcb5ae75f51fdeec1d5d8d299d8c476454307a23efb830022a477500c02f2",
456
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/subSpeak.xml": "06ff8e0c15b36727265d9f80c736a1781438c04445e91bd563b73a1f9ed4b501458f7e3ec22607dcd96e9f95da6e6d874c39381ca061a768c2b664a1b4bfc504",
457
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/subaccountCreateResponse.json": "7fb28239b065aab21f14d158e51ab6bfff6b10de97ca558da02adb639fd15e99343ca54277d0e0b0dc6be11c01abe6517fcc2f0e862d5a3538342f86bea87994",
458
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/subaccountGetResponse.json": "929de7e767657a691c8bf34be8abe52990835f9787114256bca7a1fd6016b34798d36e2318ad3d4a2a8931986d8034e2310e4b4247fa38a84314658402aa3bc3",
459
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/subaccountListResponse.json": "c57bcf1f52d302550eacbe5492bbb1cc17bd399d03b6c83971bebd83fa8be975e97859063a2115edfed47f622adfb413d5c28d6cc180710211bce192d867052c",
460
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/subaccountModifyResponse.json": "a06022b797598bdabfd7029128d9ebc9934784edf77175292c17b60152e7464938f78ddb8ab2883e0da22fdf94e584d0fe8d766c40228bc0a564e6ce76c39365",
461
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/uploadmedia.json": "35f19877904dd5eacf97183a286db18153002e37159f6e007c9c70644843d73963e9293a5e64c1854665821e36592f5ca11289d2ece86fafb3ddc4b8b758dc4f",
462
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Mocks\/wSpeak.xml": "05cdd9418d049dc33432e02bc305b10635daf3bda936c695c4136bc4bb8167ac63e6ae809202a566e5a1488d8543c06fd9c52f869b03a474bfc3db560769c00b",
463
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Resources\/AccountTest.php": "8a98fbb165ab60db8a7423252e78d9db1da922dc2e1de9ef5cde32488c04380ab01e8fe53f4f542c602b28e574966adf58385456388fb4aff543dc04467de668",
464
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Resources\/ApplicationTest.php": "e23381682056702928ea1c587bf8241f71743e4349cb30b621f2c843711c108c0811689c953ecd52515b2c780c50c134f959e4ef77ad2c0dd65dfccfa8c79c2c",
465
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Resources\/CallTest.php": "7aa7df68b91782de7a8ff67ce4bdce917de03ce4800da2d6c103f0d1297fc26c09effbbb7ead06d70566398b8679c54246213c4babefca43976c289b8bdb895c",
466
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Resources\/ConferenceTest.php": "3d1149c50cc760ec57de791d7a1eb46a5210c113fe91e1756dc642d2d94b333067c9c3c5ff9d0c90d9ad8981963394d332287b57b84c634c8e4008ec5cb2356c",
467
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Resources\/EndpointTest.php": "aae4c23a72674a9d4da6261986147a3b3a1c5e4da03d2efe7f4ec21336e03d352ddc0f7e47dab3c9b4063a170d37e0eebeba649ecd1159d85a3c5553789c51b1",
468
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Resources\/LookupTest.php": "c436483d9ad54681ed44ef7a6b44d4899d06b7b421be27d2a076aa4bbef23a5d160d5098c60d5c380a8e66ebf8245c917074edf6a7b682d056f9f60e082de032",
469
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Resources\/MediaTest.php": "a6ea3f17046c123698c0b8fc1e7cfca6665159166dd53b51d1b5a7700373527c7346a90e67a382f4df26ed3f92209790c3ca93c0c3d3b653d424e17a1fed9f17",
470
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Resources\/MessageTest.php": "9749cc39c4acb64b49150958745f19952ffeab648abf06ae839eccf8eb9a6c66bea62e7d8fa398dc48a79bdc97ee063df934ba827632faf88f4aca01e5432181",
471
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Resources\/NumberTest.php": "9123fe40158482d314279a729e4c5c0eecf3733884ea39df16de986e775e93e90b8d9c7ad35fbde8f3d4cde3e02b33c70ebe87cbb27039615de8213cc27aad47",
472
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Resources\/PhoneNumberTest.php": "4b52dd78392c66e1d1803a278ab98bb03e4bfe5275e28b043e4f672357125b4373acece1c2c5668081be021a683acd2796e6ba5ff2646baf3435dda1d6de7667",
473
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Resources\/PowerpackTest.php": "52a3c6967c93b1b996abb3fe7e40ebaec915e58e715c6943b0f5ebd945c8a59023184dd1339cd044d2f3ef1a0041a61559a41a3832bfc222332fd85bca8371c9",
474
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Resources\/PricingTest.php": "91a088d32f726c2eb49160363f7a77d351f3f65d43a9282cbea646310e2d01a33d22a2adff9ce5795f949bd205c0b6e77571f0a231265514704f42bdefbc51bf",
475
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Resources\/RecordingTest.php": "353008dcfc66ae09e915787634877d598930e60fff3f1e6eec0aa5590881f66d78ebd79aa1ba2b2a20409e4b9372eef9ab28406c9fd29f95ca6c773d8c83fa63",
476
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/Resources\/SubAccountTest.php": "6dd803629402c6f7b8d923753477f6c03d6cfbd50aa59fcd63556527cdbc3d932557b318cf8c7a9f5a9d3ff8ff143ef15f31256e488fa8c35cd62bf80ae04d5a",
477
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/TestClient.php": "8917a380e2cc030228dbb37a7a3aaedd2cd624d8102eee1fc3469a9838f31f7ee734a40cd45e510d63bf4c1526da4bb3af8d45bd4ebd4382cc9fd5bc2ba178c1",
478
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/UtilTest.php": "6a66cd73b0cd403f64f8a4752381964bbac7507b4449e81c9aaa64d61db244128c604a8995327dd8e8ccc8a30cee7a3a57fc617b845ebe65a65ac38125ca7394",
479
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/XML\/BreakTest.php": "740c84bc38e7044f5138e3816b72c6a94bca3accb592733421578a6eee2080bc6721d85cefeb8b6f1db751e2056fbf722e0dae61d260b089dd803e72cd9cc0d7",
480
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/XML\/ContSpeakTest.php": "f3b641231907bf807c5c09b65a13409ea054b0116b9b36f5bbcc2bfa651592ae1f4707be5780c37c5b9f1516044a9f524f4ca829cd0b5387a6a32526ba11cc94",
481
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/XML\/EmphasisTest.php": "b76b6d0eee048b44965f87fa6f59614e64d885864ef3ff0aa2310746d76304fb5ac6cc6d0c714e7560e5472e018fd0183cf9a918d3e4ee5415723314d7d219e6",
482
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/XML\/LangTest.php": "1a4ef409ded7d9c7abd8c63994dd3e221b16bd1fcca8133ce43e04b300a28468cea68e430098393acafb78e537e37b0574644735cb84fd08e33dbd828e2fb071",
483
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/XML\/PTest.php": "9084715ad9065f1a926e8dfdabc5816b16a385dd5cd74f16f6fdfd1aef043b7d344d9cdac4b9dc43df85e8e63f329909553e20b86d995d9eb6d25d716fc5fd1b",
484
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/XML\/PhonemeTest.php": "f85a3119f95615c3d3e16c0a4c1d2aec7b2191629b60de276cedb769b23e11546fc27fff57e329c1ac6cb52868208d29f88d1412b452932b573d88cee9fbd68c",
485
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/XML\/ProsodyTest.php": "5aecbb6cb41b0269b0895e580bf87dae24703c3116dd39774c11d52406635f4167bf55ed0b950cb4d8af9138c03361161527c7f0e08867053034d8aea1fb1daa",
486
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/XML\/STest.php": "55343bd191ba9b88fdafcc409c1685224cd6673225c1ecdc006d4c3643d9e4f71fde0a07ead3f1bfda80bed486f09a7fdf42e16cf3d4fe66f592bb72397320bf",
487
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/XML\/SayAsTest.php": "005fb0efa4803847719d9e7d52438ada0026b3860d7143fa4deb96a80826ff0f8608b3dd9302617547dd36cdee5293ec25570dd6513cd81a921ff483379574ab",
488
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/XML\/SpeakTest.php": "cc92de5d0f5df6de17b121249074752bb191265335a6e50dcc4739fe525cc9d0014c187a7d15cd0c1226c56360277469ba10da72dc56dde01f478acc510a8dad",
489
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/XML\/SubTest.php": "5c113371cb363691313226362512772facc38c30afdc32e96976aa309d6ac33aa32bab7d4ba674cd566182641048434dc65cf1403f25ea4adfdf6c6793db2fc9",
490
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/XML\/WTest.php": "f7cb4983bde61290a90fac15c009ff1780b02fb81c8568d0e8a1f40fab97dc1ec2245cd477b5ec669c6f54e56bcf7351e38c09caac7255756174baf4070c9284",
491
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/XmlTest.php": "58317dda536a0383749d695ee8cce6f73d6ab413984673d46b10d9299e5a70c6cc464051e986b75c849286787a8fb23ef15e8bdf6bbc9a27e1c0cadf46a1bcd3",
492
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/bootstrap.php": "fb1c83cc2a11ffef9903eaf721f4cbcda4767f70368be33a0980aec4e5b515fa8258750f6e19fca0eff6843d0294de9c35b8e95af0e62f51a94442be0099720d",
493
+        "providers\/Plivo\/vendor\/plivo\/plivo-php\/tests\/phpunit.xml": "74191aa62aebbcf797167fc2bfb6bb304cb3d309287a73919caa1c43c188dcef47a1f1905e56143952e4b342ef183a84887dacd6976c18e58025582d5f672035",
494
+        "providers\/Plivo\/vendor\/psr\/http-client\/CHANGELOG.md": "82bb81ca074204aff5d95ac5d3edfa9c85569c8b9114f809e3e2f9525a6046a1276187ca42f638ed428311631791f60e6dace74cd60d77f1af0a41e9f76ab2ac",
495
+        "providers\/Plivo\/vendor\/psr\/http-client\/LICENSE": "3e0ee70fc857b6dda26ef2eafa55ef09384d82bb2f85b4289abcd94a60201c698eb477dcf03a73858b2cbb9efcf00affa199e848344b84dd4a4c135601e886ce",
496
+        "providers\/Plivo\/vendor\/psr\/http-client\/README.md": "a8fc38f5744eb4c1f14f5016b02108319b7cceea7fb3219f57f0604a2e92778fa9be6f1e340003b095f70c962aff0b49ccfb0264b26eecb8fa7782667e62cf3a",
497
+        "providers\/Plivo\/vendor\/psr\/http-client\/composer.json": "b767c510e3dc28fc5c8c0debf4e5627f4897940d41ced88cb0c85284c2e0765f49305997407e84d87154a4d9e14045e6c50fd86163d3d7452294af8b7bc36ccf",
498
+        "providers\/Plivo\/vendor\/psr\/http-client\/src\/ClientExceptionInterface.php": "33aededf573747615cbf7b8bc6aa10faea7762c903a0cc98bc43803043f9bad58460f09f7301814c22e95f2a6d0269388d8ca899ab76fcf0f2bd8d82aea5d9c3",
499
+        "providers\/Plivo\/vendor\/psr\/http-client\/src\/ClientInterface.php": "11b1cee24748c4ed1a41681b1b6e43e865e08150be14452de885daaca737f4029d65e8381632a23910789d3cf5e9f9d02f4999aad62e4e8c80a2fda9ac96a4ed",
500
+        "providers\/Plivo\/vendor\/psr\/http-client\/src\/NetworkExceptionInterface.php": "6d3d81d18a51f451e8a1b74a16b3ac8ce6c5642013a2d1375ce6718090de5369779f9d6f594675aeeb7bc3f55a11f1b9396036354c4e9ae0c90183ff369fd65e",
501
+        "providers\/Plivo\/vendor\/psr\/http-client\/src\/RequestExceptionInterface.php": "46391124b679cd54538ce5ae6b05d7fcfb6b9ef7680f33c8771f94b38075a366788293b757ccc674060d615783476e1151d0ab8a5f2a10e24578c9b46cc1433f",
502
+        "providers\/Plivo\/vendor\/psr\/http-message\/CHANGELOG.md": "5567e49c016bd259491fd13a96e5b88629fe67ccaa0d75f7aa7c54096edd663fc743930eeade981a041cf7524d9f65104718c129fa36a200397d30c0e5d2c954",
503
+        "providers\/Plivo\/vendor\/psr\/http-message\/LICENSE": "22ef0ac33682fbed60a5274a5b25991308decbb45c6ed45fb3222cc045bb9e552fa7310b1ab6f38329b63f53a02c25e7bc5e955ad23c5bb2366b417563cb71de",
504
+        "providers\/Plivo\/vendor\/psr\/http-message\/README.md": "d58ab57a3e35e51848c3c21313836c88eaca950eb5b716878ba950ad2389bdd84b24a5fd8e6b19ce3ff04b07d879b5206b0f26d5e3a63a5be19beac0e9ccc1de",
505
+        "providers\/Plivo\/vendor\/psr\/http-message\/composer.json": "4f074821b6fb7074c418bed0fb6232677a0cf6ae5ddf24694e14bd5aa7fb3610a645f2221fd024e7c4bfe3e95501421455dcfbbbb38468e9db442b8cde9471a7",
506
+        "providers\/Plivo\/vendor\/psr\/http-message\/src\/MessageInterface.php": "b79e96e691ad169d4d70420953ccb5933301ce7cedc17d4eaba859dbd56719008198fd201e3be1606ea5dbc78b559f1d86ba17b73ab7e843f0c2f0b49564147f",
507
+        "providers\/Plivo\/vendor\/psr\/http-message\/src\/RequestInterface.php": "f54aefad46987c6b4880d5f09f7e99909e6e2a99f9d305d1f73e4de58b43493179149912352869e50fc46e057f50c78ba7ed5df6280a7c0347f3d7c36afcbfe4",
508
+        "providers\/Plivo\/vendor\/psr\/http-message\/src\/ResponseInterface.php": "69d177fb504f47ca0181ab35e2155cacf16e77535d07bf4eb4d790e1ddbc7a133f3de21eff936a3e75acb704c936ee2f2b12b2cf3516464222c3d60ea9760488",
509
+        "providers\/Plivo\/vendor\/psr\/http-message\/src\/ServerRequestInterface.php": "ea36ff66e8bd962e468fb2bc832e70f7bbd81f92dc0e607cd69092b737609d565f3e254a2d54fb3588f5302315f62e53c6eefe9299ba4b6f1f53ba8feffa815c",
510
+        "providers\/Plivo\/vendor\/psr\/http-message\/src\/StreamInterface.php": "11ab8a9d07beea1f1633f8f6cabb2a463ff288555f2fb8a4cc0b99404d8580493018557a0f2674feef653be51f6fb8d9aa3ad8e6dede0391cadb7bb49f96f781",
511
+        "providers\/Plivo\/vendor\/psr\/http-message\/src\/UploadedFileInterface.php": "65da733a08d80c5490fec8e69c7b56a47efc522e720a2ddcc673bd74c0e21f5fad4d522ad47da4942d25d139b5392e0882de32b7fe5a5697b86f40fd96ff0f8e",
512
+        "providers\/Plivo\/vendor\/psr\/http-message\/src\/UriInterface.php": "0d46735005331a3489e3ef4c8229307320de44b0443ff74d238cf8f3962d83e99316da9435259d479b48477d33e8713dd3d1a1859264c22f2a53b43cd6adae2c",
513
+        "providers\/Plivo\/vendor\/ralouphie\/getallheaders\/LICENSE": "ba7ad111dab105773d8a75d20024b48c4222cba6f7836b7b608fddf34f367cd218302829a1926a675bfd22660f4562b0e9a679d15b41162412924ebcc1a4e557",
514
+        "providers\/Plivo\/vendor\/ralouphie\/getallheaders\/README.md": "48ce2def80836640ced369db92da9f9e943b319849cc89441023bc260edd6919c710d08c91fbdf04864c6e08bf89e60a397f5e814b3e9699b48df574f5799522",
515
+        "providers\/Plivo\/vendor\/ralouphie\/getallheaders\/composer.json": "495b111d0e0b4f4496ccaec984dc89c897f189a67d840c09b0cf17034629e1c896c37c4ddb1afdceb7d5a188dd0d90405ce34aad409d3b7722169628411d3ca4",
516
+        "providers\/Plivo\/vendor\/ralouphie\/getallheaders\/src\/getallheaders.php": "a61a5f91f21a68108c7e9c8eef22282e4b1b6f6f14ff997c5f47c83f39acd08ec60f4b9d25d306d67fdc68ec57c7f71a44a1f63ebf7c25b40ad61fa1cb4e58a6",
517
+        "providers\/Telnyx\/CHANGELOG.md": "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e",
518
+        "providers\/Telnyx\/LICENSE": "8756122099aea86ddf6f176a480c0454f2be6dd278e475bd6be7d7ab3d572162f1bd44c9f623e52e53514cb15336be6e84a5eafc8e2a347b481ab5799ebd6e17",
519
+        "providers\/Telnyx\/README.md": "321748e1de717ff62ccd3fb2c10fbed8ce92a66271f2047c83be8929f965c179cd163e429175b44893ae30addef3623f96659b98528a405a585f7afc7394e866",
520
+        "providers\/Telnyx\/VERSION": "7558cccb74c98362a480e1c0ae17e711de8e5d6cd10f508a31395105c0efb22cdea79aa6f9f6f890837d519acafc2cb3c429d3ab17a283e1992e5aca5053e25b",
521
+        "providers\/Telnyx\/build.php": "485d76b827a54d8455550e8a8f8d14862f9444381da251e66c2bb8ceaf2106a554c1cd339666b1260450749d0244d6b9ba0c6d0a2220ab2411aa4041fc83f8ad",
522
+        "providers\/Telnyx\/composer.json": "7ab90dcc0b5854786b213e5f2ee8c8030b21f65b2f8d0f74a3aa6d771ca1054ae5e1ba58ad6684dd1234e7eb7244be537cdb0a6888172cffcdaefcc7f5908dd5",
523
+        "providers\/Telnyx\/composer.lock": "1e4b665caeb711f94b1e7f0ce6388e91ada9973159c1230d4e60f0dcfd44ba9af2dd236e6acaa27564e91b4a89dde817d5a73cad8682aa9cb93b203f467c6be0",
524
+        "providers\/Telnyx\/data\/ca-certificates.crt": "66816e077ee99ceb9535a472e6bbf4f0e48ca838099c8a97c7baf3297fcada9a43016ea1ded63a455ee56a8f18501417a0f744fc17b215bb599cafd76b754518",
525
+        "providers\/Telnyx\/docker-compose.yml": "1fe4c651e406095f0ff1bfc196406d473184bf53cf80f7c67dc79f1aa94b26db74174e0e9bc47adc95eb2a5f6eb950255c4a5cf44ccb7029ba712df3be9e6384",
526
+        "providers\/Telnyx\/docker\/Dockerfile": "a63d1fabd8c19fef37b90922aa4bb21fbd1094635666cf2a3a4db47009888bfd3f1ad5c34c05184e2ccc8f581971f6dae91c1ff137730821422cd482c39e9390",
527
+        "providers\/Telnyx\/docker\/entrypoint.sh": "2bf3911c365a271fc52d17a0aac1687abf52e5286a5d52cd34367e18651dcfd6ef1f791b54105b7742f5d691564ddca3c05a9ba4ce8edfbc68fe919e0bdf6c1e",
528
+        "providers\/Telnyx\/init.php": "e590e355286b775423b39dd23b5aa0d3383d8a85ed2d1346802e0c487cb834154b4ba1b0ca41ae112ba81cf5afbcc9133db8747e08565c00fa3b0ea04fa7ccbd",
529
+        "providers\/Telnyx\/lib\/AlphanumericSenderID.php": "c6f7d381cd9901af59d67c66fbe6ace0729c77ac2b2962ce41351ed076cb39c9049aeeb72ba0e3933ebce4ab8a936b86a7e21d30a1c07b2b08cad9da2abcda1e",
530
+        "providers\/Telnyx\/lib\/ApiOperations\/All.php": "5caeaf5bede40fa19422387d224255ed534a866638b22a7a832111cada5496764bc0434cb1aa7365e1d4e0a8ad55545bb05a42a17ae5f2b361ed42c12166a229",
531
+        "providers\/Telnyx\/lib\/ApiOperations\/Create.php": "811f9227ecc5acb172e8e7120541227de0bc22cbf66a41490b743b3e49647a38889d5cfa5d64139b602572f0fcc0fbb96e3971c78801ed9acf7b50db2ab7499c",
532
+        "providers\/Telnyx\/lib\/ApiOperations\/Delete.php": "4c03010d81be8014694e366cf93244dd2f73dfb38fe8a1f3066b6ce179b999967de5a9d3e3140b3076d0dbbeccea329ac750ebb93915ced1e44891ab589f0c7f",
533
+        "providers\/Telnyx\/lib\/ApiOperations\/NestedResource.php": "390efb020ed7c101b32379716bc2111e83273e2a7092da61623f85295c67ad1f6ac2fda617ec91eb28d02ed52a86db9992ee044356f3d96aff2e3474b16da601",
534
+        "providers\/Telnyx\/lib\/ApiOperations\/Request.php": "5b947c7171a05a754fce9c5bcb81f93c1614db086fd4ceef9be1a57977f8bfa7311af0a60a2879d8cb9380c64ddbf7c991738e5b5a4e4b2feb5d88e25c822f3d",
535
+        "providers\/Telnyx\/lib\/ApiOperations\/Retrieve.php": "d2a5aed1aaab9421f2f2b41f69047a70bdea46082e118cd94e087f4082865313d7c67aa037fac194063c53b06d9dccbfa5e65582a9adbbcaaa2982396cbda01c",
536
+        "providers\/Telnyx\/lib\/ApiOperations\/Update.php": "a102e823a46dca1eea6c0bd67b4b7c63bdc0d074c97b42a830de18006782309d3c5f77103b32e82c778f670aade73d3c31f49da49682d9ac204560bd868cd526",
537
+        "providers\/Telnyx\/lib\/ApiRequestor.php": "617ebb71c97dbd896ad736a4e1235f784ea7b89dd73a980a2b259820e3dde0ae935fa532d1fc8e0d9e14a63f843e880e074319bab2f9c519c1ec19467f80bbd7",
538
+        "providers\/Telnyx\/lib\/ApiResource.php": "5adbc90947859652ee20745236c330c5a3124edd3140cb54cb2d4ecb46409d4d825024708b6bc0a44a418f181fd5631a65b41381aae7a55d7c98d80ca9751b5e",
539
+        "providers\/Telnyx\/lib\/ApiResponse.php": "0d292d053a85224f4ac839f54253decab0eec5ae9861ca95314e98cad0fec2d2f0a7e712a8ec433adb302b6702d69262c8866b20fd08d67b2d18571965bf6789",
540
+        "providers\/Telnyx\/lib\/AvailablePhoneNumber.php": "7c82ca4fa28264c4fdd910c71741270657e52cdbc760343339bbb7c1d5980d27b7af476f7e1bd431926d428dba685a6e34d250f9678ef0a4e3cd8c4b06289e55",
541
+        "providers\/Telnyx\/lib\/Collection.php": "8953b7490974401e598cfdba09be005dcc037ff74d7eed660d11afca7a45d62c47f6b6c4f31b3b3003f3d9401599283122034362618a9c3d487eb131d05cfa13",
542
+        "providers\/Telnyx\/lib\/Error\/Api.php": "5c496f65e000a74652c5e7e3c79303befb693e497d67dab4e13287ebe72722c9651fa04c4de4065ea969e140f7a2f74ccaee2ab728f05790ee26200558d0085c",
543
+        "providers\/Telnyx\/lib\/Error\/ApiConnection.php": "469821ef557d096a088d2997f762b4a39c82c49bcf22ca707bcbf611b20006106522150d6365835e0c7e23e3303bd407d78181fb7b5d86bd35095645e68da158",
544
+        "providers\/Telnyx\/lib\/Error\/Authentication.php": "e1c7a938a695fcd8602e5a972086989efd349a6d8d5e3abddbf6f548ba2e1f9bdabe708b5ea75474f7c3588ba7cca8a1dc60970a8be70a80962f90342e67c13c",
545
+        "providers\/Telnyx\/lib\/Error\/Base.php": "9d311a5445b2f3d9c4e25c42094734c3d6243fdc5025c7e5a609ce49d2b2a47f01ea2f163154917f3330e1a92d30a736319c4daf3ae18bb6ddc41d131afae0ff",
546
+        "providers\/Telnyx\/lib\/Error\/Idempotency.php": "cde2f56479baab53e74c6784878c7914e7393b655bfdbf7a36e0619fa9c521671c105c3d5002983b3759989a22eafa0bba7b4aedd4801d7d6b820842c0285e35",
547
+        "providers\/Telnyx\/lib\/Error\/InvalidRequest.php": "0c5748224174c20020155c9f0c734121d07c752460ef63648b08a2392bb6d8b6ff0a9eba13ed1cfb8988545f6dc8c70930de6e78da03c63da0e59bc5fa109a9f",
548
+        "providers\/Telnyx\/lib\/Error\/Permission.php": "3a03b08e77e6fd0897de16d69fb3769707f6fb46717b2a00f1282d7b3e33527f5ca5ea94b6df03c883ea177520140ab2dce4986e0ee0977cce8c375e8a5011fd",
549
+        "providers\/Telnyx\/lib\/Error\/RateLimit.php": "0ceb884f1078559f5bbfbba6153e6bacd6ebc49dac2d047da9e7c64d45c7cff0abc067711366aaec74a4f2736b7205c02ae9de8c214871a82ed1fc53faf4be73",
550
+        "providers\/Telnyx\/lib\/Error\/SignatureVerification.php": "8aec6ea46f62c2b6ecf845cadb726332f89a6c0dd92f4864ac71ffd25268b2af0468cfa83b32a24e91c735ae947498bdc6181efe09857c6bfa799cec721dadda",
551
+        "providers\/Telnyx\/lib\/HttpClient\/ClientInterface.php": "f47e88048bac320e8cabb1b61869f138f84a04858afc3b7aff4de858db9b3efc507d1607037bf07ec5fb1f1df4069b71bf8ec1d0edf953bd1eb8255e67651ae9",
552
+        "providers\/Telnyx\/lib\/HttpClient\/CurlClient.php": "fed4939d221213da7fa7865b4405e5c0b7dc092375e5acd890bfdf178baa6572ec7ac7ad57cb02caab5af24d2aa52763bae1b21679f3b94e6f7ba659cee7a438",
553
+        "providers\/Telnyx\/lib\/Message.php": "18acf4bf51ec27d330df16216924c65a45db59895b610a3c803ef1d09beb7d96d20753b4ec16be06ed40f2886ad46bb3d866f14a87021484ede5d33ac1a93c4a",
554
+        "providers\/Telnyx\/lib\/MessagingPhoneNumber.php": "2a2caa5e44efc5de92ef9b0f8ed0a68af1ab2c80932f4cd7fe79caa87ca1e146af3bd0e1d16d977738da2a3af1fb3cef77081c32a0dac50bbe8ef54a108efbc9",
555
+        "providers\/Telnyx\/lib\/MessagingProfile.php": "351d96a913427c045f534b6993c37fa6ce2ecbdd7a398502ae6447d631ff322ce146cd73dcd1161c999f6bc9ab9764221b4bd3567888dd14c110b98bdc4432b3",
556
+        "providers\/Telnyx\/lib\/NumberOrder.php": "52067d9999c150fbefcbba9969b308bb6118eabe25bd08f30cc4978cdebd68fce4479e53d71ce29632133e8c69bb4ce9276301f5a36ea95bd77d29fd057f5d46",
557
+        "providers\/Telnyx\/lib\/NumberReservation.php": "2b44bfa3fdcce2e21668004d458e9e6bcdb5e33cc37e9a0c980bbdcacec945dc4e06e489bf5b9d0194df00229a79e39bc2a62395d44e4072473441e258841baa",
558
+        "providers\/Telnyx\/lib\/Reporting\/ReportRun.php": "2a7b066db83e08b86e3da4c0b2d041c4d53ce0a1fc95ca3dab76ad2bbf549d74f9a97974be6bbbf0d7b592a814a00b514bb26ad13c7621b5c229f9bc40abac7c",
559
+        "providers\/Telnyx\/lib\/Reporting\/ReportType.php": "92ad055c626d39d9f878666310ffec1c425d4625af9e7803547d50f1684c166ea1dc67d79c35580ae08850bb6e570a81994014e82f4d4080377cfbc664c4fbc5",
560
+        "providers\/Telnyx\/lib\/RequestTelemetry.php": "cefdb55dce61e5f276bd49f6b49e57c78085338537e56cce6fea5a81cd1d2235f1eaa78be326cbd513117be88a046177afb628659088b66ce423799995c53709",
561
+        "providers\/Telnyx\/lib\/ShortCode.php": "4abc882d0dbc72becbff07212d17b8e1383b0efb43818a7eab983fd2a08c3f591a4f4ba2f185003fab0622a43329c969d2fcc80b23cb94410007a0879309ad49",
562
+        "providers\/Telnyx\/lib\/SingletonApiResource.php": "f11599b789dfaef76ef6cf10bade1b426d2e16749bd207c6d08ddd007fea470fdbf0492f9a59cf8bc9f8589aa4532cd6c3887629cf27060696c3f086b0a48673",
563
+        "providers\/Telnyx\/lib\/Telnyx.php": "4971ff61049149242b0cfdca4a15dce213c465ee697cb444eb47da8215eddf2737508164c59393bd7661cf40b1a525afa9fc0df0dae8a071a59f3646a5ec44b9",
564
+        "providers\/Telnyx\/lib\/TelnyxObject.php": "a1bb11b6bfecd69ba694dd34d6309707e916ef45edea1e81e160c572dc404aa4e16841f3be7a82b3965037efef24db7c7c9730fbb65d26e8a188d30fa9af01f6",
565
+        "providers\/Telnyx\/lib\/Util\/AutoPagingIterator.php": "d03ac3841bb553d847be9ea73ab9debd8c1f2c829b0d38ac4416a121ac535a5ece2ecd9943d89e720cb5abb1c907ca9b96df899a561c190ccd6843bde785114b",
566
+        "providers\/Telnyx\/lib\/Util\/CaseInsensitiveArray.php": "bcdf3fba35ae234bc63ba6cdb5429aaa5fd6baed85857991abb9eff854b23eb7a878184ed038636292ac470b67f91c6bf8d79c20a6214d31c872d22fe51833a5",
567
+        "providers\/Telnyx\/lib\/Util\/DefaultLogger.php": "50a69f9f6ad628e489a05fdad0df811c926c957c301adb0b4b906dcce9733a0598f6c2eb126865c54a0100131dc4230a834b1e98275237ce8e90bff2e96cd0fb",
568
+        "providers\/Telnyx\/lib\/Util\/LoggerInterface.php": "8d2dc2c59af5e625eaeef0b85b09f78a42e533b62fee84717d67a4c706fbacd94674f439d3ac60984c0a3947b7d2f5a8ccfb64e071c41d063b8298f57578f88c",
569
+        "providers\/Telnyx\/lib\/Util\/RandomGenerator.php": "292c880420b28390e3d734c6343acd48f322db0c474f80430402916de1dcbf8e988b3d2753a7c18e763e632f474284b213ccc8e8fe4e52f00569e72728dcccb4",
570
+        "providers\/Telnyx\/lib\/Util\/RequestOptions.php": "61a13e62a72e7fc4a1f4d2a707d03ca785af36dd8566e037efa4b1a07d91debe1bccc637bbae6ab9dd836b20a4133cdb7316d6c2628da0d13d2164d6613f1e3f",
571
+        "providers\/Telnyx\/lib\/Util\/Set.php": "1381d2144748a490fd27329fe231e9d3a9a8b428499d4005f9ff18a946c350d8dda1ea90285314a1a99f5d351b1b235ad37a74823c37d7345da8af528dbbba87",
572
+        "providers\/Telnyx\/lib\/Util\/Util.php": "d7c35dbf5a2832ced6059800a6730fbe75338252641edab902adfb134a179d96e162f05bca2902c6c2d99cf4827d5b89b0daac826162c7d460e17017ee405606",
573
+        "providers\/Telnyx\/phpunit.no_autoload.xml": "06ad2f4fe0a292902757629f5605509f32a0d1dca527550619c98a61519d83fc70f3c886b12f5e5734b1031186fd9c7fed6fba813cd816b0f07d36c2a6bf11e4",
574
+        "providers\/Telnyx\/phpunit.xml": "82ac037adc20f2aa76682878094e8bffbfe31782dc6a94e2987bac5546e3ffec90577d03715f4ce481cc977685eec9e4109a61b4b46bc19351c2cad555d7cadf",
575
+        "providers\/Telnyx\/tests\/TelnyxMock.php": "e8e93ca1114530cb7e9cad46eb20e32072934496d515a9391ce8093773450dd60f3288f9d3ba46533a0f650fe67b508d5e54bbfc6e1642443d1fc043b88eaaeb",
576
+        "providers\/Telnyx\/tests\/TestCase.php": "9945df738b56e344648cc00d3d4b94345c15d8749ce511b5095a87d5e52aed35d8e3c773276d9dde9d9fa04eada784a55e4876ebf70a198ba719c8e94c8c32d8",
577
+        "providers\/Telnyx\/tests\/api_resources\/AlphanumericSenderIDTest.php": "1db47c5c215f1dccbc0456035edb1619cb7575dfe2b152924a6e1abe4a021bf63be3b1d1cf1b86285c5425f5df46c8e396cd66b6ff6a27534e402e145e5fb194",
578
+        "providers\/Telnyx\/tests\/api_resources\/AvailablePhoneNumberTest.php": "823ab5138035a84a790d70c9bc5964e7aa163f195aeaa2fb50d2cfc7068f1a77440f09a134bec36a187cf57cca6c735b428b225239a263aa26cc5cecbecdf6d5",
579
+        "providers\/Telnyx\/tests\/api_resources\/CollectionTest.php": "af248a4d4c4504f5fb7148e8f5ddbce3a05cc859a761f57cffb8335be10b07ef6d4e808002601f92eff2968e86873fbbc3fad838420db0694f81b9cd95091452",
580
+        "providers\/Telnyx\/tests\/api_resources\/MessageTest.php": "a616a69339b599526dfd24a25d8e99eefc99c2341bb7d4f635d1b4984f41dc38a3eb6bca3e4242caccb974b141a490624669b5c2b2f5315b6cb07540d74fcad7",
581
+        "providers\/Telnyx\/tests\/api_resources\/MessagingPhoneNumberTest.php": "40409c270a6f9a683bc690f6e91051fe1ac4c8a6cb1b4e5536416d64fc3f8c81f327f33e562ee94cee1481e0ec2f13148b0dc3f76f3f20a49a9d80adfa5c1afa",
582
+        "providers\/Telnyx\/tests\/api_resources\/MessagingProfileTest.php": "1ca7abc2b47f221b491ebbe7def5569deada6eaf4184bd6e6327f7bf2da15669d1fff581e24c466621e8462e816c0a12d02e0aa1d91aa3746092f8a09a9131ae",
583
+        "providers\/Telnyx\/tests\/api_resources\/NumberOrderTest.php": "dd6e4382dcdb0cd60ded9d9db6262bbc7f523e8f5eb842e15655fe8ba4e24ad5192b8be40bbc762de2c62de3aeec31e1373063420a99e39bf02f5bf74915d5ab",
584
+        "providers\/Telnyx\/tests\/api_resources\/NumberReservationTest.php": "8b8386c0e044e120b6d60f97433c9ecf0ddc272f805034768300bf01bfbc731a3f6f964758e509d650013df03bca66eb1db13fa1a24315df76ea55fd86287fd6",
585
+        "providers\/Telnyx\/tests\/api_resources\/ShortCodeTest.php": "8aef092868b89adda6517905c7f05245b3c39affed4c7723e5a32cf17b8e39528e8925923aad4b2add5a0bbce9049a8f934141b87a790fcb002eaf77aa494258",
586
+        "providers\/Telnyx\/tests\/bootstrap.no_autoload.php": "cb002f7c8f77834b6414db6535f083bcd227ee6085363fa3cb0f66b55226680a45c8562fd8458249868465957b2aeae134b3379f8ee2ed22c96425475e9c0af1",
587
+        "providers\/Telnyx\/tests\/bootstrap.php": "50e143ed68aceb91d3e119d5a31521e76bfe9876bd780c90ac83afb7ca4f32be48ff81c33c134109eafe1d22f35e0957a9a834966b8853df99dc1df04795adf4",
588
+        "providers\/Telnyx\/tests\/data\/test.png": "6ad523f5b65487369d305613366b9f68dcdeee225291766e3b25faf45439ca069f614030c08ca54c714fdbf7a944fac489b1515a8bf9e0d3191e1bcbbfe6a9df",
589
+        "providers\/Telnyx\/tests\/openapi\/README.md": "0c54fffd5b7a5f393358864ff9e3bd3793075d6060cc1336603b2455d60f16d160ffd47b52bca6834acf0d9713855b386f69580099a3dcc131e8d5d617975ff2",
590
+        "providers\/Telnyx\/update_certs.php": "46dfc1129c3dff2211cdd8274fadd8629c450e94a7a1c8527373221b25a0664b6043d6b007351ac9afa4b40ba349a7fdbf4ad2e088cf0a8d864f7cbb81145fb9",
591
+        "providers\/Telnyx\/vendor\/autoload.php": "1d4735a3ebfd65901ce478f8bb98ac576ef9ba2706f17a1c6ab125979a882ec7ff463b577fed1c418f817c1a56e842fc25b6aeb8e7ce6dcdd554a25e03959c3a",
592
+        "providers\/Telnyx\/vendor\/composer\/ClassLoader.php": "866e8cbde808b4e7774c5d9e2bdda44e84ff9bc84268785aff1a75277bd7918dc26ceeb27732718c9ea93756777ec0d16c09c15f9c1179be3cbb410c7914d295",
593
+        "providers\/Telnyx\/vendor\/composer\/InstalledVersions.php": "86ebb1216b59b01b7cd1f3b2e66311cd6295b58fab91a9a82603f903c6d2f716d7697a82d625372538f809e9e45f7dbd257a00e2b95d23c3785e4eeb3a6ebb60",
594
+        "providers\/Telnyx\/vendor\/composer\/LICENSE": "f3bb64009f41a425df5a9bbab53490f0eb9b74fa8d6aaa2f57efb928edc4ffff330260666edeaa04a91fed708c3663371cf01b284f3a08d6698aaef7a23f355a",
595
+        "providers\/Telnyx\/vendor\/composer\/autoload_classmap.php": "a298b75d605ec9a330a5efe11769e79f02cf202f49d8b241afbd175c7fcfa0ac4db8e72a29aa1d839138e3b181fbfeca525181eb57e998a4a2c14ec9e457cf1a",
596
+        "providers\/Telnyx\/vendor\/composer\/autoload_files.php": "107b2d75757e7b39e2d279e373fd4291d57e91a7f442b0f880b51d07e7119beb9d41d1cdf916131bba717e8da953e2117ff83f1bd9ef850fc1d9056d0f02996f",
597
+        "providers\/Telnyx\/vendor\/composer\/autoload_namespaces.php": "30324cf2dc20c214c5b5c8fdc2099b67772149ddea1d1d51969c711be9a83d036e43746c600f958a6b49969b16a10ef93e9b1e3d5af9714721ead916b9aef344",
598
+        "providers\/Telnyx\/vendor\/composer\/autoload_psr4.php": "02804e683dc13b4eb2ad98284be2dff3eeb97f0ae9054c3a45641ce7e6144a3b5f34ae36eb764fd2faae39fe5dd4131b4dffd4649c6ba3220ef24aeab45efcb4",
599
+        "providers\/Telnyx\/vendor\/composer\/autoload_real.php": "469f95fde429006c3262cabe72cd49970b0cd6098b743d8e5a646af25679dfe539c98d3337b51a8faf7f30d9c64e1def8d131a93e8897f801830e7e1c4da5874",
600
+        "providers\/Telnyx\/vendor\/composer\/autoload_static.php": "4845f043e32744886f456f358ea87cdcfd641508151ba6c3b0169c9aa53fe111f05b78b82e204368da01da68d7007709c9140d08dce4e7dca3cc4c9f60397dcb",
601
+        "providers\/Telnyx\/vendor\/composer\/installed.json": "5ca47a408f164e118f7ccba81577933913002efce47331f2eeb13f3e24d78878521db08454026d270deaa6552095260d745f0a424c91eb7efd36f6a9a20adfba",
602
+        "providers\/Telnyx\/vendor\/composer\/installed.php": "38fb24f1f4e4aa0435926d601c7b78797c231eb0e3621e370b17078645f5d238a1d02da3a29cd14a9125f78f53964445f4326311f6e830cf8faa24e944215ce4",
603
+        "providers\/Telnyx\/vendor\/composer\/platform_check.php": "4d385b31994301facce94382fa007a56ee32268d2e1cdbe7c9f9cfa834ed4195d3cf8e8e7c9a800c97aafe2c9b46f3c1a93e632c7415e8a9e4a282c083cc6f9a",
604
+        "providers\/Telnyx\/vendor\/paragonie\/random_compat\/LICENSE": "0c0bf603f7e196edaf56d02acbb2e14df7f73a2da0617d62b5fc811f088c29865ecdbc7c6925a19bda63132cc651c56f1cdac79dfa02aaeb3fcca49033636ee0",
605
+        "providers\/Telnyx\/vendor\/paragonie\/random_compat\/build-phar.sh": "a5ecc580bc6e95a9c901ad1a0097fd47ab857dee79d0221ae463e27f27cc8b2227e1975ab2699b9d0782f0b0396ed9b3ac0106f53fe61315cd2954ae54beb333",
606
+        "providers\/Telnyx\/vendor\/paragonie\/random_compat\/composer.json": "c400438df2f41ace7bff40d284236bb06c6095ac03b58caef5b062e7ef317bac5a6bf551c94459ffc838acdae7df6cdfc615dfc3cbecd16be37ba67bd948415f",
607
+        "providers\/Telnyx\/vendor\/paragonie\/random_compat\/dist\/random_compat.phar.pubkey": "e8909663e5350be2fa9416e28c6b179c41e87feab8da0d6fa6a41c294c9b00e8cc40ae8bcd03997770056f70d946315fd530f72f42974f63195f14b3c675e3c9",
608
+        "providers\/Telnyx\/vendor\/paragonie\/random_compat\/dist\/random_compat.phar.pubkey.asc": "f07fb9c7b00f297e73127dddb1f3986fcebdb0760454765f6ce0977347919c0c74ea197ed310bcd86dca7ed227812bfa6d1595c44e40f10c085cbcbf602e163f",
609
+        "providers\/Telnyx\/vendor\/paragonie\/random_compat\/lib\/random.php": "fe4539e2b55b47dfff1e2256c91498e5a41a85e28e42d790fdbcc42102c16abb09b0d7a0e2268ee004c555e1001241a9925fab1eeaa16c11ae2188e1f01540b9",
610
+        "providers\/Telnyx\/vendor\/paragonie\/random_compat\/other\/build_phar.php": "370c622746a37b65aa6e36c2fb94486b4fb01f2db3f3c9539a7fde711d1abe3f9e9c30bc61f4200e6da9b47086c207b03cd7258d77dd2ea6b48126a618e2fa0e",
611
+        "providers\/Telnyx\/vendor\/paragonie\/random_compat\/psalm-autoload.php": "f05ea11c8e973ddffde4d60688b161701217ac8e5c9237cfb57babf7113482d5e19ea441f5092eb1448a21b95ceed75f994427d6febfe0de100c376ed17e91c3",
612
+        "providers\/Telnyx\/vendor\/paragonie\/random_compat\/psalm.xml": "88c631fb2f70a79d0e56a4484fb7ae8b6b3502ed2a9599757e7a3302c42b0adfc6f0c45c9916b88d7430f209d8934b6121221dd8b424dd913c49236db7ef01c4",
613
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/LICENSE": "db260eb10b8775cb408f675dcbe11bfb1a738d638f4215467df6c4bd03b8265dec7712fffa30dbcd38b5ef944266c3963343d033f497eaa6dc602f55fdd8729d",
614
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/README.md": "82f123f85b02a7e91c3ebece404b85ef5a0950e0ca79bb0841735a5a03b88d1a3efed4bc8229b3ee1db245471cf58b81923ac9800586ace3b794421f379f7bb3",
615
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/appveyor.yml": "ed6f025871e47d5afb1eda2e0705a2185670c447279cadd8c0fa796779fa2f1d7a5f17efaf6412c403e40bee345ac3224a45f9aa0e5143f06ea5e25ba8cb848a",
616
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/autoload-fast.php": "a40c6c77f211a2257d3339ad80ae7197ede8ba0a94c76b48052cfbcc8ce903959dbd8e3434e6660bfce2c5e935cb9f38568f96cf00819d03f4a1c46cd6b7b0b1",
617
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/autoload-pedantic.php": "c1a0e8a5b461135bc58ebf0a37d75e865d9e44ce666aba9a95d6416cc7d57a834aae6fb6ef4a9cb4176690a4e41cdd8638106a11b32a155f3a8ca3acebf7a504",
618
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/autoload-php7.php": "0ac98043c8df48e7bdd3a20c11688ad3702a06271687e1019c2a7288288532ea593e7e462635b806c0b18dacbb8f2bd6d9c700a61d2b1deb90eba0b49660b008",
619
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/autoload-phpunit.php": "d34cda9cd77a67d93817d5b9b1bb51a13521b2539f9a8d0189debb1938934df1d5fd51fd2a82c9d4775f5a8613708a1e78687fab86c3afdc356bc4b02045bc66",
620
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/autoload.php": "91c2a6366a27a76a0390c69dc4cf061c73cb03a22a3303aad673cd08e8cd659c7fa7e6796acdd9d2d271f015eb16b15663c5d21d8a538fe14f459519c9f9e8d1",
621
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/build-phar.sh": "5bc154a32c62797e85b82595da69ed11676d98deb9644b62a12d5ec169d3edfd4d3b24c67170143f12ca63d9bea06cd0803f68d5e63a7849ea9c4dc9483f7b4e",
622
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/composer-php52.json": "10cd40189c6ef385b9e21311b8b2bc8f7943273552227c8006a38889d743fde82c8c61286484d59bebfb83e645a87cf6d99f29409439a1057fd16a4ca7727417",
623
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/composer.json": "e9b03b450c47dc1a593e35493c7c80c373f958ac5ddbe89a163f15e7a30a8139ac0f9868466610899e3d5e5d573d517bf09acfc68d2b9420e3301b39e7736aad",
624
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/dist\/Makefile": "1cb0cca3e1413538bad70b8c8a22dd68d17bcb6450e0c4ee41fab9fab09c36bffb4816dd0f7ea2f40ca1b4cec6b030c5c0cc17955d2c83ec08759e748b04d965",
625
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/dist\/box.json": "47543b120abf7596f26b58f9911963e9bd0cbe2297b65d43f74dc52130e503ce09049a4be53146387b7fb42b7640f6577e3c1f4862540d4f8a0e668b0001e62c",
626
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/lib\/constants.php": "4e0597dadc39ae7b81e46ef5f3f045812a11753d9116215bf0d905e0bb3760bc44639988f1ec8f0ae8998f507e0c99eecbd19705f5399edfacb87172d7a577ba",
627
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/lib\/namespaced.php": "c550633d5dbd23c1bb2fe9a14b787e239bd5fa898932ddb8a1b1f8909a57393e01f12337fcc53f54b24bc48a97c3ed89de03da089ffbea71ef90d48c5091e200",
628
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/lib\/php72compat.php": "85b52455b2764ef4b80d60b8d99d5f65264b2a2e7d770b2ab05871a5aad213ad35f2cd755a8b5d19b5ddcea758c024175480f2dbc89ec75dc86ccdb453f5fc25",
629
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/lib\/php72compat_const.php": "177d6b1b8fb5286842400019be1465fa0438e06dfce2fbf5e93e93d0715c161ad07c0c31c17394cb0c6673a058f34544454cc0845893242dfb5a998655c93701",
630
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/lib\/ristretto255.php": "f2c36f65a9a556c43bf9f2fcad02f1c87c29d89bb5b3d81634112defbae7ac0c85e558fb3b5a5e74d95906a4b543e7a2cf16fd444ff28888ef09d73fb9e6b6f9",
631
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/lib\/sodium_compat.php": "75e3119fb1d400aba554506a562c64c1b1b82e66277383bf307406fd1f4c68499a32b82108529d5af99878890e3551dfd1fef1ab62ae86982c27dc975dd39155",
632
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/lib\/stream-xchacha20.php": "4cf0cb7bf023249c18f2261057f994faf8c4233022651285fdf8978fe9a71d7eae0511ea1f64faf2f3fcb1ae5b010112a5a4ebe8df9fea7ce908916cc2ec90af",
633
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/namespaced\/Compat.php": "7a8389a0ca9cb8e544b7f345c60705e1cca41769105531211219142f15c83bd60b442dbe8bd62042a5fddf31040a19ba1f3f00ba6c2a44c3160089a2605099da",
634
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/namespaced\/Core\/BLAKE2b.php": "91aa0293c7c821d238f36fbb1f4327e67a718b53c13f0ea0f4d6e1d1675618bdadf183d842d4dea103017be863d40762a20c644a4f3619c7549991f11a19445b",
635
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/namespaced\/Core\/ChaCha20.php": "7e09160954fc59c77890f28e75f7ce8b75fdf08b9d5461c5e7dc1f49bc664bcb1b7ac74e3f5437657a20729c2db965d968060b27309a4a06a252d22b7f8dd4f6",
636
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/namespaced\/Core\/ChaCha20\/Ctx.php": "f19f61e54d42bf154182d203594613371f430d7c78f5b8229cb9bb94e19e42bb9a8e434639accff18497cd728ef391a1128d0145b8958f8d4350ee340340df39",
637
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/namespaced\/Core\/ChaCha20\/IetfCtx.php": "41ac6fb53ae553db13ef5c12d8c1c16d017267f130e8a00e9c2a8ad10d723aaee5ee08f2888f016babe4d712a0f1fa50012e4ebe6626b34973c26ad6728e36da",
638
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/namespaced\/Core\/Curve25519.php": "5404d91b94a8e6c442c3eb30b763f1dd0c1234b845b967b7048f71d5a0b6e1ab287b44f43e06ae5bd6fce31f78154b8655353d7df86b6ac699a41200b9df33d7",
639
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/namespaced\/Core\/Curve25519\/Fe.php": "937defa56e99d4f38a81b88c03c649deca5b0f41f5d0b8e340cadccb34ef0677563f18967bb9f63e9547137a2a1827f9e37c62005fe745aff3764e39adf86cee",
640
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/namespaced\/Core\/Curve25519\/Ge\/Cached.php": "3db1263681f9414d237a8318c08ad07bbe3279b7310e21a40c22033f5d90eb5d7074dbde430eec7910a8d7e4286fa6c0131938c92045520f56fe6acc37af70af",
641
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/namespaced\/Core\/Curve25519\/Ge\/P1p1.php": "d757efd8638aa0c1609d59c47f3b18608a0fc6e1e5bc3cb94f16fd3fa2d6125872a796f4837cd8b940ca6988db92d3c668bba684c721476ee5fdb6fb6d50670e",
642
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/namespaced\/Core\/Curve25519\/Ge\/P2.php": "cd70c62efef16eb21967d5bb0489dadef845fb3cd4faf0b1bb7d080a8685164b2b0fde4d8865dec22037795eea6df605dc2151f20871c31d5e9e0084f0066219",
643
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/namespaced\/Core\/Curve25519\/Ge\/P3.php": "56c14b848691af72c00f5dcc3d31281a300d0ea9b6ec273ff929cf30d2279cf34d51891729a5b095445fffa8a63b8c8147f4d1ea24935c86b0216b3c40aa4241",
644
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/namespaced\/Core\/Curve25519\/Ge\/Precomp.php": "f6c53daf36931b4289248a231da52759e91e5c38af10b2cb89a1bd7e55d29e316dc77d144fb9e52ca1cbf50db84234aeebf13603c62d58d5b3ee58dc19cc18f0",
645
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/namespaced\/Core\/Curve25519\/H.php": "c2e48f6273cabcdc40f20fd0f7ea55975fc9da5a419b1c9cb834b694c858533f9a0d3e3ce768b532ea6b69ff5d2df1ae4c246a15b7129916d4034ac497ca2be4",
646
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/namespaced\/Core\/Ed25519.php": "eda61c7ee144449df655ea9a9142d0b26624644542012652598bdc51493f61938c13651b32b05e942d31d3cfbfb7899b8621f4ebd8a5909a1ed12704b2bcfbca",
647
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/namespaced\/Core\/HChaCha20.php": "b5005439c15ef7aed83b566e670053819f59c415d9c5f607550c756622d7161ca32fe65dad8f688e6a292f88192637260d859302064b416465c08bbf7f6dbe13",
648
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/namespaced\/Core\/HSalsa20.php": "c882b541376c8eea8ab3bb63d8b51dddb345cc45ade8d5d264dbaa96427f72f0201aea828e696808155da7a978c4a1fad09723d42ec393117693e48187cf2a4f",
649
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/namespaced\/Core\/Poly1305.php": "c438e61d6b330be26cff863f8b5c42fa3284d6e8abdd1e43a2023c2695dec643d2641b2239a9b0fbea1a34e9e8011d5094b4eb024b111b6fa903a1c026328747",
650
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/namespaced\/Core\/Poly1305\/State.php": "4558eb5b05c7664408a4e793c2b85a4c2593ab8a1118c3b89db712f337a12346e2e882a0c638c32af733f5589a310b4a528c9bc02c136692ae82f3ac7e6cddab",
651
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/namespaced\/Core\/Salsa20.php": "2836d7eeeec597187c456ec790107a5dc478a1f79c1c1e4ede4314bb830f865f189e048e3dc55742703e2fb7bf31275f515cca57ab5bc47332961bbdcac7c490",
652
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/namespaced\/Core\/SipHash.php": "345fc6b9f37659ec9830c9b3bd1459257b81568dc73809c023c551dd825981b0da6b150b6b7cd57b00097ae9cd3b742d730ebfda2d2e459ebd7d5257fc967156",
653
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/namespaced\/Core\/Util.php": "81aac8187fcd44a14ae856e34d7337c012ff3603c606e1b9ff5a95fd5cdeb962725b70672a57b600d344fb2f34aeea00ddc8f1d4d8f8888961fae9171f8262d1",
654
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/namespaced\/Core\/X25519.php": "d11fca34bc3d313e365ca47981a0efb880a3cc8be3e2cb00da7df69de8d52f2f1fc793c1654cce1385ea66aec40eb5339c5cbf120c127cb399b72fe84b7297c4",
655
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/namespaced\/Core\/XChaCha20.php": "de5d7f3dd4402fe3c99b66a92fa4f0766beec66928c8996b3754b2f7a8869b65035c6ebafcc8ba2fe9b309adf541e89eba9491554f1ba548af6139770aedabf8",
656
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/namespaced\/Core\/Xsalsa20.php": "6abb7e9217d5463d373023d5aab49c41cd3e1026835985dd13256e68374ef63b90b7dd033f7fe14ea60229a98e5e64d0d0f23b7a382ecc9d8b41746bbe3fec11",
657
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/namespaced\/Crypto.php": "257d3d05f1acc745b21f25652ddf0b09b5a68b2b75abaa9216bee10ea958f8ed1d3c964dda5326216366d9cca4a71e8678c23994fd07eca2582e3d8c8aa75500",
658
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/namespaced\/File.php": "d7cce5179670dc18544eace3bf8b8b9863e62fc9520526da2870e45d5d400004fdeeb3c0f44a90caf0742f89b633e7fe3f996bd5f89af4c7f52ea37f429e453b",
659
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/phpunit.xml.dist": "0f8b25b7effe47068dfafdc568c3298d7c5f2d4eb1abc040c8dcda1b0daea8523a1f82d8e00d6475ffde3cb566c18d17ccfd07db59c72bda11f40d555b692d32",
660
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/psalm-above-3.xml": "5bb5402c96cd45a0d88542bfaa12ee03c26c3242f42f1e33a2a32e5a16143e6b66e7dd4bca7cbe30f73ee9eea7e72862e356f1bc4c4daaaaf1ebcb248d63b230",
661
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/psalm-below-3.xml": "9ef67d2d8ee81c94d0ed80d592894be0c200045b295178f246865d12a54d963e97b4a8d75ab88595bbb73d74c75ab2275a54b9a33733bea2d15487c5894f515c",
662
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Compat.php": "1c233a4b931c13b00e243f699eed9e81fc683846e089a24ad90dd17f786bfdec9ab32509eb9666074c9fc2a168ea8d411144274e6c4d4413996c78bd3c536515",
663
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/BLAKE2b.php": "27fdd20dc655cc7f58454cfa97fb974e4d99f6da5b97d79e669d41b9c5bfd1be18fa34f0ef7a353731a3bebb11b56fcb68818cabb3d8ff026682e7b39106c6f5",
664
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/Base64\/Common.php": "c8512fc6d570a3198107493c7b8d20f38539caec221adb14161d7efbd6ab7d1d0bef4cb5528fcd84cd9484f1a9e0fbeb45aaa2365012680b0106ea92f8873281",
665
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/Base64\/Original.php": "4564f7cfef60c318abe626832bcd355cffbe04d020e04d18c5554fc1610c4a1b0ae8d1111681e2a458ae0b9d7ef3528bd62aef019fe3c1a3f9d28b5ae58da86f",
666
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/Base64\/UrlSafe.php": "dcbd158a52f33b9c64c8046c8f091d9af95657a562ac694c9ac0beb3a1876d55a3f23cd42c1777d9cf2a55cdae38d88ec54628b2d5fccd6befc92d4d51eaca2a",
667
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/ChaCha20.php": "f0015a4f95fb6028c015c954992233d76ff0b07c7c60de6347e7b7ff1cf704e80de4ed5b3e236502fddd3c56071aa8012758d905031d6154f965c4898251329c",
668
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/ChaCha20\/Ctx.php": "aeb8c31a1bb46b8519f280f23d349fa93911bf766715c0964c0a901369d0f0599e87c6e13459734f582a04ce74d9ba9f3ed7553d4b7214855a815424a8a8610d",
669
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/ChaCha20\/IetfCtx.php": "d22a84b5bbe07297fa80c989e93681b27b3ee502a9b77b63e2b08eccdca03cb98c39834feec5fce3cb0e1915f2944b06e94fe555da123de982fedc61b30c1f91",
670
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/Curve25519.php": "b25ba0383cbaa00339f5cbaff6b400a25f3bd4d244d2fe70a08b987ead0ebb04a7f51b9476baf01fea5967610911f809114e39d21d4e278a9be72b48ca39b09e",
671
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/Curve25519\/Fe.php": "0fad7d424e7f3fbc0abd6a4f9113c83523aadc3f9d3423a94da0954f56d31705ca567ffad0972794bfbba00c4909c8638130b99a983cc52022d262d6b7d145bb",
672
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/Curve25519\/Ge\/Cached.php": "58ed8181f08dd61076c0ae9ce176455d951de04b9b1b03260c593d009414e9757d9120ea9e94040ddc1e0867f8a6574dc55e3acf82f946100d03d4506c9f778b",
673
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/Curve25519\/Ge\/P1p1.php": "63b5f5a6c7061826799c2e3285884ac2108adb19ea246475b98fb68a26aebd694eeba56191fe15fbc1a9ecb9b85c139bf9e8b65b4456b8fb42652fcf29097fad",
674
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/Curve25519\/Ge\/P2.php": "4caf0b912ad4bd82f8c447fc25829177323ba7af6d2355a7709b8ef99a855b51158e5252a1739cf6e9ae72b780e415af0cf3d510bded3fbce3542c99cf057535",
675
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/Curve25519\/Ge\/P3.php": "5bd84bc8087c48e62e9d29451c0165376ae8486ad9288556c81e4cb897822cdaf95a2df6093f16e2a336839d0a4ea7c1535361bf041d8be0fddeb1eb245eae55",
676
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/Curve25519\/Ge\/Precomp.php": "a58cbf2c93a75948b4576395ba1ebcef5a35b6dfb4625690e872010a44edd92939ba146b145cf40bc2cb6e45da0e19f169a45b575d813a70428f171459ee2d8c",
677
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/Curve25519\/H.php": "0ce669e4f370acdbf6cf27d5a525b0a3a3bb7c794b8a2ccc7b2f3a3670fbb048a8493e3e6306a5f148204f50a5458d47ffe4a2705520e15631b02d45d39b0676",
678
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/Curve25519\/README.md": "3f50765b54a3cf172c9cdaf2541a54273b811df61330af83883de5309103d6309a0900ecbae056f60aa831e438543c16c809fe183cc15c6a2f2bf15f6f910cf7",
679
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/Ed25519.php": "89eada60bdd8739af528cd74b771a2ac04e36aa3e588549c7e8a82d2267a4df5eb4ef13c806185ac65bcd33fcba0f49a03cdbc03f143ffaa576ba6f4ab5efaa7",
680
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/HChaCha20.php": "e221d5f3c4818256a895cc05a8e68ae2b3cced7eaf4e425f3c373d59b2cec31fa7b498e5e42af7e374e70c3a176f966da3cccc4be97b646182a8bef2817986cd",
681
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/HSalsa20.php": "05e5376ceaa53ddb24971a43ded855892cf37fe0f03647660f573334ca79e61edafdd511c418cdb3d42e62298462e729c69b4dae3eb802c4749774b43d659536",
682
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/Poly1305.php": "1bc3f6e6323d44ab76eca14cce61e7043ee98d8f7c50f29a5e29704c35adee345faaac767af588e1c6566f5732c1ec40ea815c51711056737460c9143adef1e8",
683
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/Poly1305\/State.php": "9a69f92ff7c3e384cd57c0d5fddf9111d57abc9849acebb329ffd1ac4f53e539e1548140f4a430f628cb378d7fc980494307df13e4d1837b0af377bd7811c6d5",
684
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/Ristretto255.php": "c4fcc5c22d8ece4e704c847ca01ce6edba7682fb2b9b91d74d664a204cd5955128c3bf8089a855312244f28c4ef6953927832ed989a03edf6eaec5c26df1722e",
685
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/Salsa20.php": "8c2ad19b46f527ef9c091cbab17f64d36610745ef32f778e3911e1aa2a142e88c0f6e005ced046a678d66982d2e9ca48677f082697af3999cb62fecee4d800bb",
686
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/SecretStream\/State.php": "629c6f96a7bba323ddb8eb422e7048839c188560932cb4306b9f11ba8a2b15afdfc037fc14ce8725ed3efc72c26700cf6cd2ca4a85870fa885aad6b6d57a4a0c",
687
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/SipHash.php": "6f24cd7d32eb80c943461199a0937b0acdf01560542c54ca916fae6843c3dc5fa65d751380434508aa50501f7dfb6c227e9330996956c4a8c8b32b6ae55bebba",
688
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/Util.php": "fe12c7259ad5daa7eecd8e199c77f822e612333169878309cec5b5483a9bcc775261c344a31023c2741d53f37f05a0f6dc6289dc45c7d7b8ac7fedafd5458d57",
689
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/X25519.php": "ea1d665ec23534de7f18c4f48094de4463753baf8b9ba011e38b969873bbaaa32e6b90bbbd0597baed3687c28e37fe394c224a229d734671b7d7e03197d039f1",
690
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/XChaCha20.php": "56d827be22c68fe9a2cc01b9f5890846197c5831c3c0f129d9b8c522391b7d7391a217a2dc48a4bd78e81c3d2f3bd8187546d311f991148fdf43a8a67730c81e",
691
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core\/XSalsa20.php": "c0367d97622bfb654340a6a7948e8ca4ed399d106dd8b27169a9f5d9bc6532129548b4dabf9f12ffba654f490b8adfa07b0b76935bda15705560feb7c590a3bb",
692
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/BLAKE2b.php": "97cb339b44cc54299394b4fc27c8ab13d5a8d48aa4c8fce71733a27cea5d3226df4341bf9722fb4f4ba71c38f5491d677774245d75bd91a693269aaba0487036",
693
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/ChaCha20.php": "da693dd0be25c739b477673933d361ed4b2f83110ae98f7c6805af20789fb4379b4b7a4ae34aca588666cfbdf61c2dd5776f8a4b1ee0215dae64ea09c6479a10",
694
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/ChaCha20\/Ctx.php": "621194fbbe2eb42c04c9d94e45e3a0ebafdb4cd87195b924705f8c2a9e54c9dc52fa6dcb39967ea1dc4ceeb6f2d20659a1b0aced8035529376f6244ffaa96f07",
695
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/ChaCha20\/IetfCtx.php": "b4a0690f9af7ace9fb3f8c10ca78989573a1cd49d3309f9c0011501daa3c44f7b616868e417096076846b19502ddaaaacb7c85f9b5c8622c57e4882982e09a10",
696
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/Curve25519.php": "fd10531c29a88f84f8b7de7c09a0e9e66472658827bcbdc55dcb1fba54f620b32dfe9359788e67abe4f6ffed3e4841e6b74939d7504188cfda243512a86c7eb4",
697
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/Curve25519\/Fe.php": "e6e5ce11b327d42167d51d2fa462ca6a54bf180229261af9ac1189fab30941148136ddabfff606dcf656985cb9da9bee93902f1863a84a3e5d42bfccbb0111d3",
698
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/Curve25519\/Ge\/Cached.php": "350f529a5a178921a2f40818a1668c3effdeac12b9b8aded2f57f1654343d0f7f535c780c5a271d9b7772969fff9381befcb85aaf676650c67b6e583d616c064",
699
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/Curve25519\/Ge\/P1p1.php": "fc8344d196cfa17fb61ab576b0a73f0ecbdfdf03de53d669cbf56bf10cf13eabd8c8a83d3eab7d9f9436b4dbb8d0785f9929c190059e0695579811405f3c840a",
700
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/Curve25519\/Ge\/P2.php": "6c4051bff3e25a7863fcfef3b9c1f028fa8b94d301e4de5dcb6654c629bc95f44978fdb697698375e3cfd1dfb9ae6a3c8dfcad0bd5138e51cd5d5315b5e5b788",
701
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/Curve25519\/Ge\/P3.php": "d6ee2e6bd34cba83a2025bd79e2d8a829d39f148c65ceee5a382662ef25b1c684552e0486ca29215f52d5d1e140176bdf6e2c40febd55970db55675b76d448e2",
702
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/Curve25519\/Ge\/Precomp.php": "397b94e8292ad4f09cc37f1b08a7f364e12d6acb74f125ff0148c5562631f632a2ecc44db517cbd5ea61865e70732e6223a0c736b831c751df859a7d2afc4ae6",
703
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/Curve25519\/H.php": "7bd14df9e3afbf8bc2ba27d5faf6ba72f17eed218cb7e89f4a458f500f6d9a60c52eaf5f1fd656d7de492246b0b0ac3d5904da319c5d85b754c64ce4b1f1b433",
704
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/Curve25519\/README.md": "3f50765b54a3cf172c9cdaf2541a54273b811df61330af83883de5309103d6309a0900ecbae056f60aa831e438543c16c809fe183cc15c6a2f2bf15f6f910cf7",
705
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/Ed25519.php": "30b970fe798803452a504ac453c70b5a2b51cf3094639dc58195b3c8e44fc37089c58bec2337d7f79ca60c91c4951af5dfa89e9dfbe3ae327084a806a6b8db7f",
706
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/HChaCha20.php": "d4fdd553cde5a1ff277805bbba85128e3ea59e4fc32eaacbc8502414148933c760ef6da06fd967bc594f9d22523c62e45ebd7cc9411ad4b76e2d76c0fc2c00c5",
707
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/HSalsa20.php": "8bbde85156bb88b6f0f14cab67840cabf1e1c456f9459edc145e09907161bd6fbea93fd37f121678064de6922102e78789cbfa3c2eddfcb40b93178fa3fbab6e",
708
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/Int32.php": "325772c5cadd6953316e83afe2a04804041292f25cb16e6027ea230e20aebcdd819c937977918161eeb9c43187fc105be2824949c9d6059e9c0a39e0cbc42219",
709
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/Int64.php": "8fde2b57266d78e8b03d8c3f89a1fbca3329bb6d0ed4526b3c6dbf5a0e92ef9d8e9e3697cd23b7eb5f7524fba7474cc5a2e06f1ba6faa04f7cb8729c985a5794",
710
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/Poly1305.php": "f0cc2f5cf32a37ad6c3dbaff1a8a155ff334995eab78ab42f2e5bd950390babaee0c1588e3f17d4e73cf970b8e3c34f536096d7da23182f526b0eed704e3ecc8",
711
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/Poly1305\/State.php": "8656ebf7aa0c2c7e8cf01546a261bf5e9f6c374eb5f40f8133bcb33e35bda2f19f47471b2ae6af6224df7ab9bf3886cc43b88049e8ddbe54b8dd129b28491129",
712
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/Salsa20.php": "bbb3dc0a30030d9c5f5ef1ef63e36f9a067d67891185b9620ebee17a67bee31a7abc420abb7b82f38e913b5de54d235859f0e8f5f718d8f02316f4fb03e24b2a",
713
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/SecretStream\/State.php": "69d505517dbbdd2e77cf5aed72673edffa2aa008e70325db88877ba5673ac3ac070bc4c19cf13707932b0b4d71ee0a9b007e06a0f822292ec278a60def7cf511",
714
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/SipHash.php": "8c3c2d2e4c656ee6f7af729856cc4c79918ae2e09a167d6d0cb92f7dc9240c0bdaa36e65a167f5b63961d9f9ac4df2c19e50c848e5a6da5855566deb5b9ab8b4",
715
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/Util.php": "d6ff44eb1015687847600f8b7f6a80974f4de1cb80224ea7f733e908fd53ba2aa669b97d891fe89bf0bb8d358c15a2bbf0661a779e68a715cde0405455127eb4",
716
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/X25519.php": "9e2d803c100fc9a3749100dda30fabe25c6ec59382be64f9995b6505e1652d5b2762111f2243b69316abd942c88106fa5239adcae842971f22fedd8e3aedd954",
717
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/XChaCha20.php": "1d4ef660701da25af79c9d4af2f158e3f62afbc1e5c2aa062f64b970dd33378d5f67c9f0172991985ddd65a976759e09f4604ffdf6ae158bd8a98f4e97af851d",
718
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Core32\/XSalsa20.php": "ffcbccb7d8a1d0262c5e74cbc679022bbcf1acf9160599ce2b92f66e261996f0e93b419231fd41ca95852e09b7a892dd8e98101c3426d30cb294f869908ee21b",
719
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Crypto.php": "1af076765319483b5e0c2a3ed9d5a12133fd41b7172cd15073da3723200c41cdf077dbee04f1e4badc2b86ee5e23965dfd0e8f3af3f52b3b584ab2f775f64cf7",
720
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/Crypto32.php": "9fd3ecc6e6faec645f2c5166ca551cbb4ff8430664bdb46c383da399048de42ab505a05c709b6ed0de245402a1abd701f21398252f059003a59fd55bffd6399b",
721
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/File.php": "4f2a6c996bd3fe4a07e4e1d49d2790e68798add08c4887efb3d7bdc7beb5ec2c1601b8e77a0b40e570211f7d3b4e5a5f97471f60df8b31434487495677052640",
722
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/PHP52\/SplFixedArray.php": "2adc50710dd4bc2cc1138b741cde09f225f727f2177d006ce8ca82691de0336dc51b6c30384938eef1693ae92628460f8984aaacf336815dea092de4ed1521b5",
723
+        "providers\/Telnyx\/vendor\/paragonie\/sodium_compat\/src\/SodiumException.php": "705f6e9777db6be71970f7e218339e36d50023abf723446195cef782976d7431f815a90d1ed83e32ec527303057287f890215b4b0a9a8c992a13d111e8bfb947",
724
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/CHANGELOG.md": "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e",
725
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/LICENSE": "8756122099aea86ddf6f176a480c0454f2be6dd278e475bd6be7d7ab3d572162f1bd44c9f623e52e53514cb15336be6e84a5eafc8e2a347b481ab5799ebd6e17",
726
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/README.md": "b552bcb37ad765a0aba888fe43d2e2f41b5bee6c90e734c365797e74dd0b8c4df017ae74dab2458edb410630299efd7b649438db57acd53fefb1723e233416f3",
727
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/VERSION": "294108697ec66acf16af2f9518c5999605a8585058ad25dc9303029fd890e6835b2fcda23fff2ad60058f8f6a8a19c945d998e4e228453d4946e395b9aa2055d",
728
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/build.php": "485d76b827a54d8455550e8a8f8d14862f9444381da251e66c2bb8ceaf2106a554c1cd339666b1260450749d0244d6b9ba0c6d0a2220ab2411aa4041fc83f8ad",
729
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/composer.json": "e05f4af7ceef33d82ed5704be36e1b9839236d13073d0e23ef77d33ce7ec303cc2cfc2ddcd25318f1a5295bbe3b61a13bc2fe72f55c226e2f072e2a0b1959481",
730
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/composer.lock": "2b8c24986c6cbd290c0ce53ac4f773836751aebfd65a2350fd07b4cf45292ce2667a54494fa098da13a385ce7a9e10a2ed55d20f7c8dd6817f93f33a6cc710fd",
731
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/data\/ca-certificates.crt": "659e8d36bcb65a7fdd299ee008fc4ecd42be87d8ae7d7d15828567b9be44b4ed8a316978f2f7d3d5d7e96a4da0b30bb8bdcfae5202ef099691daa796318a869e",
732
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/docker-compose.yml": "1fe4c651e406095f0ff1bfc196406d473184bf53cf80f7c67dc79f1aa94b26db74174e0e9bc47adc95eb2a5f6eb950255c4a5cf44ccb7029ba712df3be9e6384",
733
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/docker\/Dockerfile": "a63d1fabd8c19fef37b90922aa4bb21fbd1094635666cf2a3a4db47009888bfd3f1ad5c34c05184e2ccc8f581971f6dae91c1ff137730821422cd482c39e9390",
734
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/docker\/entrypoint.sh": "2bf3911c365a271fc52d17a0aac1687abf52e5286a5d52cd34367e18651dcfd6ef1f791b54105b7742f5d691564ddca3c05a9ba4ce8edfbc68fe919e0bdf6c1e",
735
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/examples\/example_webhook.php": "336b92a647e49d8c994c8e6dc6b26670f0a58cb57d4679d0ba7177fa1f56a84a628e5385dd4c1c25a1395b1d8499e54d34eb2c20f9742a2a2a3d0cb20c36be08",
736
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/examples\/simple_webhook.php": "ed299912ca9a55170796df76b25c5c92462660b065ef7eabf24bf7f552e75fe44512fc3fa977fae2a9dd5e9be1ea28100a456de926fd7f24c32152f577f8e46b",
737
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/examples\/verify_sms_demo.php": "042dee741d4fe90d78edcd0614df6a371cee77d1a95d34623b4e558ead69378c693a33d044f450ea204efd7253e7eeee1e5a4119708dfddbafeea358bc5408b0",
738
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/init.php": "82a207681a76c9b00d1a35fcfe64753cf286d9d0122366f8c1f3009ecd6c548369d2b65d5b4e03f20faa9502b967a3bdae30865e5bf8598eba630b5f9555542f",
739
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Address.php": "a01e1efcaab0209fa7cf32ed85722ff793b9c0f750daf7d3bcd0499037dea764f2a61defa54b4bbaf602f8d0f5f477fd4198e35d6d8b47b82fd13c7a7e70ad59",
740
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/AlphanumericSenderID.php": "c6f7d381cd9901af59d67c66fbe6ace0729c77ac2b2962ce41351ed076cb39c9049aeeb72ba0e3933ebce4ab8a936b86a7e21d30a1c07b2b08cad9da2abcda1e",
741
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/ApiOperations\/All.php": "5a6381d1492e2ebd1498fb4371b55c7e112ebf2c898e1861d7dfd2345db8c56df221795208a29b2a0e42295846fcf98f6a60fa8839df7e28fb66b9bde9226ce5",
742
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/ApiOperations\/Create.php": "811f9227ecc5acb172e8e7120541227de0bc22cbf66a41490b743b3e49647a38889d5cfa5d64139b602572f0fcc0fbb96e3971c78801ed9acf7b50db2ab7499c",
743
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/ApiOperations\/Delete.php": "e3cde9f67ab7281870c7399c4e76ff5807791b94b595567f56ee4ee494574e0f6f282a8d0c024c78c1709940198460f386ab8de6118a85de7d8a52feea0b0dd9",
744
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/ApiOperations\/NestedResource.php": "209aecf9e6abb679b4f1ec2b59b1ce363a73970f6d389829b77802cb88b7bb368506e4d0aad42f090b715b4d4a580fdbe5c8479c02227102b4d147d615fbdb8e",
745
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/ApiOperations\/Request.php": "afcba7de3fa312bc9e532e43bdcab8fcc5ca8b532c6f7bec08f94a8d7b2849467266f98af029bd688a136ac24ab2b7f438ca2fc666395c589d578e9d0156053b",
746
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/ApiOperations\/Retrieve.php": "6f29bd2711e3c6b586c2bf6d9805b986a5f76fb0cd8c98c63259cd9873eeacd679f9718dd333110966ec3bb772e2ad06da7b1586bb590180770bf300aef63c8f",
747
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/ApiOperations\/Update.php": "1d353ac81bc74cd57c75f01da21d6c59e053813930a0eb0fa054417bc87b6a140f64393bc04ac312b8c16803bb4c3eabae278839973f772e3202df32828480c0",
748
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/ApiRequestor.php": "deeca798d9ba058eced71d846bd22cac360cbb25bd1271db25cd0ebdb29b1af9ee863b362849035e8a9f6ee62bd49b8415cec97e1fc01e674ad6942ac987b6e0",
749
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/ApiResource.php": "f093051a36277165763e1ee66594056cc266fdb89caec9ab9223ae6af9add8ea4a20e6e3ea6fff4e9625fcbb95f430686f1f89db36f981d7d54034d79bf397a4",
750
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/ApiResponse.php": "0d292d053a85224f4ac839f54253decab0eec5ae9861ca95314e98cad0fec2d2f0a7e712a8ec433adb302b6702d69262c8866b20fd08d67b2d18571965bf6789",
751
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/AvailablePhoneNumber.php": "7c82ca4fa28264c4fdd910c71741270657e52cdbc760343339bbb7c1d5980d27b7af476f7e1bd431926d428dba685a6e34d250f9678ef0a4e3cd8c4b06289e55",
752
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Balance.php": "333bbe5f278ca247d8287c8da5cf3b3f6a96c896a82e3c3b54d01277e3cdc82dd5bbda2a1253fb473a29c49d3030b73b24eb8231cc34f85b0a43bd853682e000",
753
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/BillingGroup.php": "60d9fed23d1520237a50a707986709f3b700d42d049e4070a48fbb50f257a98eab779f45a15939af3d5bce811014c01abbcb86fa1b9ccc5b89d55f44c4b1a308",
754
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Call.php": "eec97591c5e7af2b057dac6e6498cbb2c1fee0439b1b7f31c2d879a5a0fdb5a3eb5ba3bb7e3c5a9195d9019e9df82c99a491ec52f15bec59b496435c0787d43e",
755
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/CallControlApplication.php": "fee499465ecfdd2d5aee0479d3770a80219a5837bed934e0930413e6dde740be21bcd965216c782e0765ba18fd71714ac69a5ee887497845ccc1bd7797d6cac4",
756
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Collection.php": "ba4afd20a921ae7c838a74bd9efcc4e468fc12ecae86b2222f97c9405d376a77533f55924bd1d577429825e746ac59142f6d4576f4d446cb3757cb36b65894fd",
757
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Conference.php": "ef9da126fc06537687947c8eea71fc34a53a7d44607d60bcaea7d8c7f55e76a94a9d7e0057f9abf7efb1f4f270680cba042112a127c2c487fe3c617c5102be29",
758
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Connection.php": "c5f43a62ff80b2e91556dc63ad2f78cd83b4fcae4a7a28ede36388177591fbfc6c20b244f6fd4e540cd9401e34b04946bf422eedfce25316e61c89f15de97665",
759
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/CredentialConnection.php": "fe9d8b7b34a24f5b3b83d6a2597359fedce871db3a526124832d4bf4129e7515366ae16517b8dae259305ae69f95655aaa8b4710a9addc23fffee0e70b70b74c",
760
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/ErrorObject.php": "cf83764f49da72bbc816c8741644e15b9a74481145c6c0c11c390221ee4c7ae485cfc09d77db24a48b0756b69c85570242bb2b903c39ca699e636a299ec4dd31",
761
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Event.php": "4e4ccaef81755432630c46881a958928c8b633ef1dea76d05f05711da17f68bf6e5b7b77395abf297b3ab128c065da7b4ed38d1be3a45306eb6d7a1080e72994",
762
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Exception\/ApiConnectionException.php": "b2a920958f3e1664a6ea5c5f32c73f9914b3f59d8a927c4e920d385ce87a6676475823729f203b09f5530da667f52e3dc3d4471fa498277270ee9360d0797b5f",
763
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Exception\/ApiErrorException.php": "b775efde92c04d1a53dd3f948f2efd92baf1f1dcb5092ed0863f37bb71fe03052562fa89349b1030f3d27a0dffa974ee47c9a3655b40a3941b05e721e7fe97c9",
764
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Exception\/AuthenticationException.php": "f8154528a04642cdd24f3de876b1a38d6f97e357d36badafd39e596ca739df7fb77f4259de1efde8bc300f126b20f6e242db4c1e3a25503565df579b62676ec7",
765
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Exception\/BadMethodCallException.php": "5e6df108c1df11bc1275948d96829f0ca6ff039126934ec57dbeee74913af00a64e6a9f2b58f42bf74aebeb94596c45cbcf66e5a4afa8924b238ca63d424f452",
766
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Exception\/ExceptionInterface.php": "77d5904b79a9a5b265ef121cd19d91b952f631ac7436e7896bb0786d9afc0b7ffe54c7ea901091baefa0154b91abfbb3f9f3a7fcfea4053f27cb44be2d7cb23f",
767
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Exception\/InvalidArgumentException.php": "f2872cf684dba5abd50bf876971e32364a23c9259c1e85a01575348614274453d00cc655b01c2dbf2c78c88f4a6143cb486c786dd1664204dc7676a64a9cac4c",
768
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Exception\/InvalidRequestException.php": "fa310ff5d5ea8f02f731089c27e6903d9b0e692a3faf272efd19ae4f1075a2a1219d167730b21cac6a30e705816c4230e2511fdda981fb47714f4d81606ffcdd",
769
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Exception\/PermissionException.php": "4cc209df863027760738530c5c01962702970a73ac7f11be232234413376dfd34db049f4e49305c8a15ee1f016b26f1c128312930e10cab174e80d6ba20cb12f",
770
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Exception\/RateLimitException.php": "c37157b02475d2a3940dc7d007b84cc3c86cab88b42e841a392e3ce4919e637c9b59bc7b33ad3ed8b4b32e74dddafd8e61a6f30d60029b8b1ecc82b8faad4833",
771
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Exception\/SignatureVerificationException.php": "3aaa44cc52efcc4caeaee624c070e8ec87b665decbdf00d8aef04ac857358028e4bc0495c4a86c504f3ccc6d753413c5ed685816e3b80851026bf2034514cb59",
772
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Exception\/UnexpectedValueException.php": "33504e45241779bae5e9c1d6ace82a75d545e6f7ae76f7d7f071fa4bbab13b2c23d11e59230da3c242b548ee7b5386bf4795e0d06d1719812348d1f9efb0c1cb",
773
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Exception\/UnknownApiErrorException.php": "cf5cc44f46c03d9d0de656e2ae61d7b077d123a4b6666a4b0f57fafa2033e072ceb5b14d6a47987bb14e0acd48ae00b39d4d6ac1849fadc879bcc43ed1acb44a",
774
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/FQDN.php": "b7d44de17cfcd207ac1fe6aada6c24871a98dadafc4cddebe28b135c6e507634608e1b6c7052a40cc750f6515fe19c2de29864d4b9551e7002fd800cc6cc05fa",
775
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/FQDNConnection.php": "527d18ad480447e4d79e567e7a91796ca31bb778f10011aa9fafafba6e769d387fdfbc306a6f1ba58e583bc7c37a9a66f1961494d3639dcdcd8912efcd0e6a55",
776
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Fax.php": "fd8af5f711fb5341e2b86a7fc66a49707bd31efabd2cd63a1d5153c24462f07341d6af618b7e82ff1faeb9bdc203f62b6dd5570d74754e052300d0d7edd0424b",
777
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/FaxApplication.php": "f489a9e161565a6e7f55a4d90fc05bdc8147a8947788a757a2b5464059ff2c49e61fa26b6d1f0b43fbf9ce8d0c08328e276442ab4d2d100e7ef34e9b2e0860c0",
778
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/HttpClient\/ClientInterface.php": "da6ee5de3e8aec8ac144511858cb3bec53bfd2aa0b5ff27eb43c7f72dcdbfb1646da223cbd861db7595db904007ff4c8d6a010122547a98bc1d2c07139328a80",
779
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/HttpClient\/CurlClient.php": "dfcbf2f40053699b94de74defc4a57461c2e07280976a377cf4ec3600e6279fa9cc434060b0291c7e10a634647e1a86e67cbaaadc49783eb532681ca25256a42",
780
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/IP.php": "624821d6dcc5d30a1a08368bacba88cc7ce8b768bb3315b3f8013606e303fa8940c13da8ece0c67a43329a0cfd86d8bd09682963eb54138f4253eb2f159c7560",
781
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/IPConnection.php": "01239dc2096fbe207ce1a5a58dad8d25795b9a8a81dbdd4290730009f2fafee76d74335aa951fb7b54e930e4e9530a0566daa9ef7e99ea60a50b8daf956f11dd",
782
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/InboundChannel.php": "c37478b08abc62ca491806db6e2814c4a28a11357fef873f6aff8867e179dc8d89817ee3db3fdaa84150111cbeb426ad0282dfd7550eb815dca100843f542178",
783
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Message.php": "18acf4bf51ec27d330df16216924c65a45db59895b610a3c803ef1d09beb7d96d20753b4ec16be06ed40f2886ad46bb3d866f14a87021484ede5d33ac1a93c4a",
784
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/MessagingHostedNumberOrder.php": "ecee6ab7a46ebf03b93870017aba4ce00c10ee36342a6d3ead209078aacf4ebcb798ae129535fb15af860355b52ea72ae6bcbf0e5261a9d66224e43560858227",
785
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/MessagingPhoneNumber.php": "2a2caa5e44efc5de92ef9b0f8ed0a68af1ab2c80932f4cd7fe79caa87ca1e146af3bd0e1d16d977738da2a3af1fb3cef77081c32a0dac50bbe8ef54a108efbc9",
786
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/MessagingProfile.php": "7a561dcea7b45a4ad4c3dbfc6baa766f011de2b2dee9a23e512689b374017b05f4fcc5c3510f19111a9d8484ed93a5e05d3dc01f35d75e356f475a894596dc49",
787
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/MobileOperatorNetwork.php": "d4436bfd9a628713889a37846829763909033339a086b6983eac792e9af42c0df2a8bcbd688c5c54a196d1fcb3d22aae7b45e9e18c015592d979e9a924c42ffd",
788
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/NumberLookup.php": "cac3b5f1ea0ca30f9121849a8aa52ed2e18b7776c4f1d552dca4c3536e0d4eb96af45267bb687319a9ec715972bc95a19c7dda54c33a2701e20cff9564dfcee5",
789
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/NumberOrder.php": "52067d9999c150fbefcbba9969b308bb6118eabe25bd08f30cc4978cdebd68fce4479e53d71ce29632133e8c69bb4ce9276301f5a36ea95bd77d29fd057f5d46",
790
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/NumberOrderDocument.php": "007830f9c03979a7811a4e0dd0c74c4b2b6d05e05b56b9d6ceb5a6e55167eb95b2546087ae17328715e01d486c0e58e396bc41816b44866391b98d48ca246d03",
791
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/NumberReservation.php": "988c853084f13e0d86445d6638517f84ef3d90c3f618c2c85c0bd8ab790012c3986a1a3eb3e00fef7759d04a6a1957bd9521bb8da6ade8c05fd2e02a8040f6a3",
792
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/OtaUpdate.php": "3c9579c6ac1ef6f31ff572fa3fb7562b3618182cb36eab3f406d8fbe6fc7b1d35a996e47923074428583ee3653aaff3792f9fdc47eabe1627f1a85722fd9dbf0",
793
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/OutboundVoiceProfile.php": "d0c5985f6f629904f4c95b892e329f280f7e0e13b8794d1950e216ef4c28ede7b94baa99f18803ff6f60b09d6178ad39fe5d3c182e984c2b4b57e9732991597e",
794
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/PhoneNumber.php": "8106765a769bf3f6190783917aa923f3f7690af5b7bf971e3dbe73ee5f227b27531a553cff9cc425ccfc7cf2ac52bcfc685f3d3b178875f8fa837a5de99a077c",
795
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/PhoneNumber\/Messaging.php": "d0aded1cbbd4c6108b0fc6e6773dbd03040af54c967f0a8aa9b2523db769317182889c882e6efe6fb0e187ac3f2919563aa6a937c77f4c1ff94e5bbc31f4d9d6",
796
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/PhoneNumber\/Voice.php": "e7e8184351cb186fee77019e88600dcb15da0435161d1878799433686e012167ab3347d7f02efb5cd511b5d02cd7b6547453f6ecaab623ed23fac7c91b0a7333",
797
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/PortingOrder.php": "ad9a683aab02c8817796e62131fa9cad6f3490d3afe231b5718b3b4f0689a535543362a88333ab808c36e9c41bfc8b7b6178be7fbd5b12f38b6d806053726997",
798
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/PortingPhoneNumber.php": "ff2e1e98371b6a7b0cc5265d1ab82f053d97711a72633a7d3911a4211dacf75c08083d6629aa4fc028643c0dc929d3ab56132f6f21808b875a9ce679e56fe055",
799
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Portout.php": "71de0eb22350f649e5023b2c4a374b3d10a4beb0f8066d67482c62f68a39219d9cda4bd95d91e1df2fc215479f45b1ab79bfc0ccc2d39267d2f268356ae83ec8",
800
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/RegulatoryRequirement.php": "0658d49bc2c20a9a16ac72ea01b5306eda422d81747529c3373333facb5ce1940252387aa498d2957dec62f0eeaa8aac3979ffd84ca72308e660a1a0708796d4",
801
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/RequestTelemetry.php": "cefdb55dce61e5f276bd49f6b49e57c78085338537e56cce6fea5a81cd1d2235f1eaa78be326cbd513117be88a046177afb628659088b66ce423799995c53709",
802
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/ShortCode.php": "4abc882d0dbc72becbff07212d17b8e1383b0efb43818a7eab983fd2a08c3f591a4f4ba2f185003fab0622a43329c969d2fcc80b23cb94410007a0879309ad49",
803
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/SimCard.php": "46289711eda27b37931b0d9f7e9624c114ef9c1e997ea88055dfdf6fe6dfaf7f9169b9a67cbfe48100dc4df2b73ba4d27328b0ca3ff0af3655789535ec3c0b26",
804
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/TelephonyCredential.php": "497a3dde2d7fcf8bf57b502c71daa5e166010daae45e30e1db7ebacb3a37028fc70c7cdcf39a356dd32f845664e8e9723a366fa69610c8f9bd31fa59b3300624",
805
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Telnyx.php": "f5ecf9589eaf7db991051de8482d582b36edc387b8a7ca48c80a419c1a99e1393d7f099aa4ad3e87adb4706ab62c8714dc843c9a8ce77d6fe6ea5ab929d9a882",
806
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/TelnyxObject.php": "0f45c91559ef686a3eb4ce3777ab7d43ba288b380ffd1031cc3c562138410d3582c251e2d986e8a84a2c189257ed4307500e3fa0d662a48a30b28a9622ae8ad2",
807
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Util\/AutoPagingIterator.php": "d03ac3841bb553d847be9ea73ab9debd8c1f2c829b0d38ac4416a121ac535a5ece2ecd9943d89e720cb5abb1c907ca9b96df899a561c190ccd6843bde785114b",
808
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Util\/CaseInsensitiveArray.php": "d5bcc37aeab4fcbbe0b9f4a9057a5654f6080ed899ae54f8ef18bfc907f244071a6693386dd306caceb6bf338883a13c7972574ac5d700aa00e22ec363932cd6",
809
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Util\/DefaultLogger.php": "50a69f9f6ad628e489a05fdad0df811c926c957c301adb0b4b906dcce9733a0598f6c2eb126865c54a0100131dc4230a834b1e98275237ce8e90bff2e96cd0fb",
810
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Util\/LoggerInterface.php": "8d2dc2c59af5e625eaeef0b85b09f78a42e533b62fee84717d67a4c706fbacd94674f439d3ac60984c0a3947b7d2f5a8ccfb64e071c41d063b8298f57578f88c",
811
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Util\/ObjectTypes.php": "99ce4f7d4d4d9d43e24f3124a7c21b9540267aa160c780efe69d6559843a12948f3790b179db66282b0adda384309a793636d71aeb97d9aab0a62dccfbe2b51b",
812
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Util\/RandomGenerator.php": "292c880420b28390e3d734c6343acd48f322db0c474f80430402916de1dcbf8e988b3d2753a7c18e763e632f474284b213ccc8e8fe4e52f00569e72728dcccb4",
813
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Util\/RequestOptions.php": "00b6d4890b5a38f42f13ffdca556bbf1377c05c8a79ad2d6d0b69b7e27deb70252c15088458da4bbd56e7832cc6b2828e261241661dc344727e2bfb170465de2",
814
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Util\/Set.php": "9cfa1c1bc6c012e8a7a797ba8a7893382eeeb234da73f93594a159f78b9858c984dec1e42da5a6cdb240f00d27d250e3fd6a7842d40c23513661201a148a6c5e",
815
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Util\/Util.php": "4556fc8b785486adfb60ea8001296ad0ae7b13d785f92d545324b557fc4aad85a69ec19dbca27dd868050d64670e4e2be2e3a4f50e4aaac609b0089c0e9e2749",
816
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Verification.php": "b63d4f9d717ba204dcedd1c3315db3300567fe09563faed0e4b8f1415171e43e0068fb06ebb2f42c808602248f623f5773414a1612539a873070f461398be650",
817
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/VerifyProfile.php": "fbdf0818dbe1fdcd6bf13720f21ab6552a3ee7930c80a9adc44c3863ebb3df990b18adc8beee6770f4fca9bcda0d514a689d051c129d871eca48f2c0eccd7649",
818
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/VerifyVerification.php": "f2883946ac990666dfa62e07dad649ae0c9de75d5682857cd22419fda8926d45d504ce4fbf38896a1cbf25323a604a818d3b89f05baf58d91cef497c54d981e7",
819
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/Webhook.php": "b451d90496fcad105eb4f61d5716b93878405315742c09d7c4be96c6b9c0427e35c03c1a664ab2f30f1288566b45117f87b069a3ce96d64111ef6a1ef289ac9e",
820
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/lib\/WebhookSignature.php": "ad990cd80d771718468e39aab1b06809a0efb9bb47f5ea4d42a649dbe481f5929fcbd502da6140f1438920e96ce2e4af82d9cfd810b0ddd0eaea391599685c0d",
821
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/phpunit.no_autoload.xml": "06ad2f4fe0a292902757629f5605509f32a0d1dca527550619c98a61519d83fc70f3c886b12f5e5734b1031186fd9c7fed6fba813cd816b0f07d36c2a6bf11e4",
822
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/phpunit.xml": "82ac037adc20f2aa76682878094e8bffbfe31782dc6a94e2987bac5546e3ffec90577d03715f4ce481cc977685eec9e4109a61b4b46bc19351c2cad555d7cadf",
823
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/TelnyxMock.php": "e8e93ca1114530cb7e9cad46eb20e32072934496d515a9391ce8093773450dd60f3288f9d3ba46533a0f650fe67b508d5e54bbfc6e1642443d1fc043b88eaaeb",
824
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/TestCase.php": "9945df738b56e344648cc00d3d4b94345c15d8749ce511b5095a87d5e52aed35d8e3c773276d9dde9d9fa04eada784a55e4876ebf70a198ba719c8e94c8c32d8",
825
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/AddressTest.php": "dd980e7890ad3dc1d12858f2d241a461689a34892bd780a8db034e620c23d01587996042c2c12d82333b2072bfcca6585afb06213694b7415b0b13d3084b83f5",
826
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/ApiOperations\/AllTest.php": "6031bc6fa9e899f06af9465468fb9e15bf5a9a7c1051fb52fbd383ea879842e72ba4b5347d07566182c632b5f66d5f2d4bdf73c1368a3581c6010330bff91ec9",
827
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/ApiOperations\/CreateTest.php": "c94c7e854a40716aec0e257c4d7fa279c3e941d64a37e167d4885dae5a0e22a513c8f3b018c436eff90ee045432c5e34b96aeb7d879380e9386c2bc177b94f39",
828
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/ApiOperations\/DeleteTest.php": "02ea2d3adfd1d83770f10dc42cc2c12c28079ca80933fbe02219ea79fe7eb6958d2b1d76cb7a0bfee9e308c01efb1eff61901e22d192e15e89ae67f7edcabe5e",
829
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/ApiOperations\/RequestTest.php": "f6e158958616f0637f827b94cce168e873e0d3be09e4ec27165f984af3d89c0be4d5d5cd3ed66df5b6237bf183003a0de1c652f599827fd01a2ee7ad47d5fd61",
830
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/ApiOperations\/RetrieveTest.php": "b26b8f61eb3cb893ce4ff9517817295fe9b727dd570b1cf79ace36e16902e0ab9f460d6b65342afa28c59236b59ec0ba0809e1cee673f69ea26489fdbf5f4f42",
831
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/ApiOperations\/UpdateTest.php": "6aafed3640a1173822ac9a26c002168eeef552f9b681fab9ec4f191df4f988a920d8c290b2f875c02596ef613273ed003e4b5a6bb6e0bc2760f54ffff445cdd1",
832
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/ApiRequestorTest.php": "5a1234c4a1e4107aaf970bf87f0fdb1420979dd575a548e589b046cd7feea4dc914f25bf15474fe5bcd9773c94184b610d06b309d48639964a78e6137078cb5a",
833
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/ApiResourceTest.php": "05562966c7ecea541b0ae95f67a11d9e2b86e45439b436b319e252d5998e0eb7a6c9b677e233572fc616caee856d9764b56feed80fd07cc1bec0d861490753b4",
834
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/ApiResponseTest.php": "6f8d458b49e34df5c0634276659fd441e4140fb4dade92b384230e4e2b897e0da6d0e82c373b1eca98770dc3396ffc8b924672ce2141426706c624d00ffc7af9",
835
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/AvailablePhoneNumberTest.php": "354326429958fdd199df78d11bbc582a0988018b8f907d93808cbd53243f50332482c0603bf4ff12db2a8977ffe7e663ea9d6e8cb5f485aece0d46ae8942833d",
836
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/BalanceTest.php": "8f866f88a8a59754e2fce7d5fe2a0bf50399fd21711cef171873a45308ff96f929b23163495c273e96c9894b7ea39ee5149c45e764fa0de3b51807a329c674c6",
837
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/BillingGroupTest.php": "4333c81ee3ac767fa600095d95f324286d289c7e105ab251f635d9a942e75c418bde60f96c5954ae29dc152ee5fe7679bc5a8b67452f5fa1f59a411dc4854c69",
838
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/CallControlApplicationTest.php": "2bb4f83cdf82457840352c5beaaed8963aba1dcb59711e310d5aaed0d35429730796b412f1aa4e85d5be5a2288ebdd12fc2be9ad75549506d1a613d604d20749",
839
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/CallTest.php": "50f830a3a3c28953ec53c244d22381910307513ba18b7199d5e7bffc5747863e4da975fa972114b2f8a81d0c24afb2f72df8315010febd8d606d086d79d82165",
840
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/CollectionTest.php": "9e742f72d8a223e64bf1a25362f9a28356c0b55037811510692880a359ee5e39266d9e76aa0832de39530e26798806929fb9ab9795a04651ff316f609e2211f8",
841
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/ConferenceTest.php": "4e8ab0baaf21da65e3942b0d98caff11b7a30c24bae10ba546b82f7031d7a85b9d88087f9ac8172e69546eb7635bc1cf8f39b509017b82116e0e13b557bc1f7e",
842
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/ConnectionTest.php": "429f80316a563f45783c87db6b6d3dd1564190b5c6a259f254e91ad8b71b2aa5e6ed40b9cf1a98632b7c89b66441e07f0285d434c78dd9729c032c7a4891d4ee",
843
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/CredentialConnectionTest.php": "a1c37f36e418debb034faa2b7df5095eee175ac8801baed517089622123dcc4af642448aecde7aa8b19cf67629de087e4995ec816d791b5007923ee614590c1c",
844
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/ErrorObjectTest.php": "97344e9d24c204ae429b856d0b32299de4380ec52e9cfbdef6090add25355d268e3dd3ec35ae7c5e0893f5bb204624930d1a856932243180bb71b40e5a1dc08f",
845
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/EventTest.php": "5152c008cb3de14a47586eeaf3ef778629b2beef87fe154a2c40c337c3f918d664c0ea44d8339e22846fedc696fe6b98f0bb0b557d3f88a3ac62990445a55ec5",
846
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/Exception\/ApiErrorExceptionTest.php": "7d54379e1ab9f7d6bddb721ea1c284a8d023674e24e99d115f388ae367250089e10b5962e2bd091e3ebbedd0cc83bb4f821eb0a986ae11487e341569ef7f5c6e",
847
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/Exception\/InvalidRequestExceptionTest.php": "a7da1818af1dfb3eaade1e1a122a8a3224e03a557396e11528af75b13cfae07764f82a282a3161d514358b4c55312193c73b5a8900fd70463fe0a66b448cc9f8",
848
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/Exception\/SignatureVerificationExceptionTest.php": "1bb0fd1563a5c91b78b02e4f66f3cf0288986f546a0805830e0d4ad1ac449549930558caf86c06cdc578279323c43e4739747961065d5ddfa198dbbcd9540599",
849
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/FQDNConnectionTest.php": "0af10bfb2398682865c4ee72cfb34425fe73b0fd20c86b51c61c4cf72f8c4d39a4ecfa21e4ae2e07a67fdf956057549f0c8c4f77e27e65dc1b75dae8b9b849c9",
850
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/FQDNTest.php": "625370468fb338819fb823fbd38656799a8750f5093eebf75c02cfb592969a8635a442ec2febfe07705a5d6feea362b7644c25c67ae653a245bdf55fc178a2ed",
851
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/FaxApplicationTest.php": "64a60460c62983cb0afc2c76880628e16270f14b0b761a8d62766cbe4c0fb33dfc7bd93ae0cb62de25a8f2b3e1994826fcbfe300ea37353f398c4cc8ed7dd62b",
852
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/FaxTest.php": "a920c8ac18021bedbbc4972109afb0cd0afc16e5d86df2fffa2f8e0bdf837e5684124f926f01daf0bae439473022899498441a770ad8cc52479da3d012f1ea1f",
853
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/HttpClient\/CurlClientTest.php": "cff15215b95a804e4ee233df60671c5c1e9270f621025f6ea7cd5a0bdbb55175caa6c43c62e176300bde05c9ee90d84efda0dcdf0d0b5dda4dab2a47d1a669b7",
854
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/IPConnectionTest.php": "6e034e287616ac89e5059d337c682e3fde010130f4403dc76fe4efa12742c40dac114ddc1aaf7ce9e553c597d9ac27170419c5e33fb1439c31c6b585953ff1a4",
855
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/IPTest.php": "7ff33e91d1c7b8bdbef1ca1f5e373150a05f709e524d5a62b000b5c8b8d697ce42306ea8df917305d9ef2a4ea19f797ca28e2f8d0d5f9e3e31c4ebe5eab55ee9",
856
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/InboundChannelTest.php": "c430f6df3eb5add5bda2342e4b4a3acd77b33d74758516782ee0a045d75e7387aaccf36017fdaef18d71cf8865a28faaa0cf07a4f31c9876858719d84d479657",
857
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/MessageTest.php": "08ae5ad7b98362fa7c1478254f851078ef7e9a223c74f3fc57619d2b9c255259edefefc400e261cceafce7072fa7457b8c1cb4dc8dda29b51e432f6d274a8c3a",
858
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/MessagingHostedNumberOrderTest.php": "f8f8ac7271fb01b07815e2a92d7a0974e4320de63942eadc12df307c9458a7cbda7ddae505a731c491e4aa6bcdda7bec04786890df80dd9acd422593f2a02c0e",
859
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/MessagingPhoneNumberTest.php": "7827d12be3191d1329168c6b277899b81df17aa18b775be538b9b29ec9a90868969c05cf61d53715c42105b92cc37977270c1a7b78bee3d13214d8ece51172f2",
860
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/MessagingProfileTest.php": "0949c56ac67ee6f87854959635dbd003391e497325305692784905987d114b399e4c648252f314bc1147e385daf4e60198cbfd6aa940a6cb24992b8cb5abc24e",
861
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/MobileOperatorNetworkTest.php": "6cdaa23aa8cd0a0e9cc43b6f17c86d9c1f7793f7eb30b774f4a8ae9754488e59e0c180823c31d062abaa356578a8718c65f367588c61015e5e36f9f98e7a5cbe",
862
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/NumberLookupTest.php": "e03a73e589abd73cf52a637dd7d273dd2477533b66bcb75685552b77b47f7b58116c4637477da7f9ccb36a408909d91d3f0d3079396aca9bee996b862f358499",
863
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/NumberOrderDocumentTest.php": "06f3e8f8e8dcf5d8c96f25a6f1888d59e9433654ff060701bcc5cb9f54b07357bb3606ac17af3e3913033fb639358df85c6d5c55bff114407168333d7d49cbec",
864
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/NumberOrderTest.php": "176ca2e94df05262e8a43f14e112fb62108ce886bd90a690e8b907881c696e35bd223f08a4960fb58ebebd20cd42bd4217ffa14132e53ddac260926c6d7e8842",
865
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/NumberReservationTest.php": "11742f7449c279908848fd493817731f3f1343895e16d3426a7a7f9fc3d4cc27e275a858e16d7efb8e9c18d32de1ffffc92929e8e3ba277157ab7304c3023c86",
866
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/OtaUpdateTest.php": "14830affab4936804afdd723714f2dc76c520fc2fd6e4d36d7bb255ef566836eafb6b29c18c5adb8785eed39f4bab030e3cd1aab1ef0293d9660b38a10fd6a45",
867
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/OutboundVoiceProfileTest.php": "e49828087e2114fb11569db7387a0acb7cce8bdb0cd655b280b567445ba2dbf16f8b66a88369876e7a2530fb282bf5a04be702719adf4ace871c2b6df8fa5edf",
868
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/PhoneNumber\/MessagingTest.php": "b3c5665f4661624f58f02b814ab1edbee5ceb8c26643bd356b486f049dbb498a44da0af43daf200890c79acad16d51c169d7aa1a2ad4befe074b0ac539ebe3c0",
869
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/PhoneNumber\/VoiceTest.php": "af08b444289d0194437c414916a8ec9285b98413d78e74d1c832b9b45583f9037832a538751628b5dc86b5a13c40c63e9dd360b719501762e8e868fcaa6fb215",
870
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/PhoneNumberTest.php": "7a07f41165e45e5fab268b0e01523c2f67f0ad146965c401856582c4b4a3f63e53324585b1785b41cbeb637d8e61e26e2bfdb57feaf6c6c04cc33be8e4864df8",
871
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/PortingOrderTest.php": "48d2ed4bb9354c772eef6484a0c9a195487c39f26bee3d143ddf64ae7da15e42e5f280a3e26eaa280940230fdee52ea09b7e5320823d4baefa73eec4490537ad",
872
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/PortingPhoneNumberTest.php": "476748b7e467c4f5a648c394eb19dbf297aebc2c16357c946dbc4f363241639dd1001985a7bb21166d5bc77bff1e31edce6e379dbda10f04406377dafcae1bd5",
873
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/PortoutTest.php": "cd262d5eae7c9ef9ba8c76856ef2d4f604484e6bf8646e9ad5231e89f5d45c8176a8ac33a757c53e4be8e2c98e6bb750c6041aefe8b2a589ac1e70a2db4493b2",
874
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/RegulatoryRequirementTest.php": "daa2836606e7c3f34fa122045e982e42f5da86b46f367ddcd7fe9b12e2a3fe5d472d4f38403d4b63aa0c58473d3b5901b8dd49b93a56fa3e76a0bdcf88ebade0",
875
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/RequestTelemetryTest.php": "61190b3601f7c2c72f55e9b1634cfaf11ca53231cf4b5f854ab14859b97f5dc0f07f6c95b8f7c3516ed253e13768b7d4ed9c1d15d0772fd1850eb894f5821152",
876
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/ShortCodeTest.php": "f2e867e0b75d8334ccce51f7bdce842b350e7028319e8d388e0512b5e119585952a54ea79762010f12de8ffcd1c440638ba5300ddbe59adfdcefc712d8e079ac",
877
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/SimCardTest.php": "7000edb2f9b739bdbd44fceeee2e4a16c708efb22c7e38483569d5416f3c107bcecdc759e2e6108553193ba99acc542f5bf3bc353ee1428593a81b80d89ad7c8",
878
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/TelephonyCredentialTest.php": "1f65bad536cd49b2df684db54533b9799856b32464b80700bed5008c9379c414f756d075ab8e231d83f5bd9c1729dba064a5ab5c7e515ca5c32e85698e2036ad",
879
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/TelnyxObjectTest.php": "6214f2c38865c7a183f6a3fd64bc79e7f04963bd726fc124a87b65412075fd236e00cb5f5ed514a3ca2847faec77f4e7a14c59e8906478543daea9c4ddecb7b7",
880
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/TelnyxTelemetryTest.php": "ced938d8d20bdcd0d465155e1bd3ffbaec8ba96a6392c42dbec27a1d10a04da17b90fd3b91322c94b54fcd5a974528e6f10d081ca9b1915a8c8166e0727ceb31",
881
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/TelnyxTest.php": "d88d70053ebb64905acccf7e3cf651ea40c9155130e351d56135c96ada96263311faeabc83d4cef1e72387302ea4a11edf338c3744093d9828e056351eefe11a",
882
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/Util\/CaseInsensitiveArrayTest.php": "671262198a48a16dc2ddb7ecf1c7fd309241db9c74c11072d86cbd2f56403973e4bb17ca5bc6c489bddf46cc391098dd6b666b134fded9430c211c2a3193fc58",
883
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/Util\/DefaultLoggerTest.php": "39942a071430588bf6c089f5d0c97596b3b46b5b7a2b45d900cc41670dcf4bcf0d34e37895e494f0c89242e52d11d8a62f419650407c26ed91b43ea18c816e9e",
884
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/Util\/ObjectTypesTest.php": "2d697994485e6c8f9084f9155a5a5b753261bcd2afcc9dfc5760daa5d4196b7c5baee49b264142a705ca7dd6c5d2cde227db3c1f860173aee6769299db95cd83",
885
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/Util\/RequestOptionsTest.php": "86d628c4b19e4b7d057cac471219603643b6405e83745535b6c5f743fe84d5cf918a273f9e8e22c5eded36cc20ce49453e90c0ae05a9ed437059ddc287ccb5f7",
886
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/Util\/SetTest.php": "c91cbf6d983f16e033eec154e56705b1d942243371df25d5cec7cb375a359faf29fec0c87fa5f3e4d7aad512d7e757361cf409e60d643fff7fa8fef72d9ff172",
887
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/Util\/UtilTest.php": "10f13d306d3ac2211b67e759a6e1fbbbdcbc1cb791db4531ac799a8f84be67b3ab43cc85498b786b0630510324bf5039ac7ed39e2252f607f7937e802f9b578d",
888
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/VerificationTest.php": "8ea7985bfc5075c0e5d3a8b0b703af578479e481d769a0e8659d4b0996314aae15de36cc7022e087c0625c5976255aae323f9ac141e9e4fef3939a23fda6d260",
889
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/VerifyProfileTest.php": "c0986530c0ddd14e2227cbf9ceb0614aeec3c3b2dc37b5bce0de0d174ebd047f61fa28ba0787b4de1fd3efb5d77d5924e36ebf6fbba09711d0237f520365e8fc",
890
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/api_resources\/WebhookTest.php": "7e06c31d714348c6c9a6cf14c4a21a1f593287fe61e41630a6d766f15cf2595dccb1cd92981578cc205f6c89839a07c7c845efca2b44521d0aa36c0be9e444f7",
891
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/bootstrap.no_autoload.php": "cb002f7c8f77834b6414db6535f083bcd227ee6085363fa3cb0f66b55226680a45c8562fd8458249868465957b2aeae134b3379f8ee2ed22c96425475e9c0af1",
892
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/bootstrap.php": "50e143ed68aceb91d3e119d5a31521e76bfe9876bd780c90ac83afb7ca4f32be48ff81c33c134109eafe1d22f35e0957a9a834966b8853df99dc1df04795adf4",
893
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/data\/test.png": "6ad523f5b65487369d305613366b9f68dcdeee225291766e3b25faf45439ca069f614030c08ca54c714fdbf7a944fac489b1515a8bf9e0d3191e1bcbbfe6a9df",
894
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/tests\/openapi\/README.md": "0c54fffd5b7a5f393358864ff9e3bd3793075d6060cc1336603b2455d60f16d160ffd47b52bca6834acf0d9713855b386f69580099a3dcc131e8d5d617975ff2",
895
+        "providers\/Telnyx\/vendor\/telnyx\/telnyx-php\/update_certs.php": "6a7fd896832dbc4c039fc907c74f25fad01f26882809d1ed0bef2870ba7db5d5930311208e2864190209862a077e4397dabcc1760ef2ec7e29127868016fc0d8",
896
+        "providers\/Twilio\/readme.txt": "879f75eaefe03b56788a884a5cb031533b33a94acd816b9e3e51a9cf0db826de700062955fc45d9561bd4c69f71178e2976f702e801fc06c3c076494c55c8bcb",
897
+        "templates\/content\/index.php": "63d6e27dee39188b80cef2b095db84791e02af0526b80d41bd37845386714f9f82cc9dafaf97fa355b927ab9b74527199ec70604480e09feb10a2b076e313b5a",
898
+        "templates\/index.php": "15ea019ef66fa303773941fa9ca673e472e9521b3f9fdb9052870e6f0596ca3939b247c8924ec0d67e0f3fee6e612e2c447a1297cf23cb5b6144e58a6197d65e",
899
+        "templates\/navigation\/index.php": "2444dc7bab057c77297dd6feb72ee473c7586a58bb7a02edd1985f75dbe92c8b300ced838295a72e029dbaba67d750fbb7e0e1689efe2a151bc7d73cf73392e6",
900
+        "templates\/settings\/admin.php": "b4866d15ab16f577c861f5f5f5a8a15944fb8577cbc439efb5c2323d2bbea925eb96643be6513bf76daa584117547f282cd5aef9c5eb06211fdf4792f5fa6c52",
901
+        "templates\/settings\/personal.php": "3800462217fe111c90f78bbedbe6f43fb6c90133c1623aa1af0e199bb5af0f8c594b23a5ff1e35dc4e9dc84c67814740a140fa7b270c8a1a6ba434ea1399b8b5"
902
+    },
903
+    "signature": "k\/n+9\/lXNFu9w5O73oZmLnsnoCNBbDK++zwn3GQ\/Tb4rsVEVYGhzcMkJKTfVGtcIoW5s6ivPeaMbJrMM+x80V7tCaKtndICjEfCFJpTv3exeQnBdT2qCiNPmRIR7f9AlLq6IwZF8ZhxbWpk3RKRlNQTEvpam3+Ox\/TQhytr\/hMbYFaMy7Nh9e9JK3jnc+341UIegDviG1Y+6ZyxSUFEI2tGTuAvyqqqnCVk2+x8Mhj0ZdrK8QZo6475tMuLTwkc0PrnSIKn51oSU12AzQ1gM05rei6nA5csoWWfx4TpxNMCV1EQc6IKyy8FhamEAeyRsoBQomhJgWB2CSV5HJuOsvb1sHxCUhuqXhOJa1kntRfDod8GPIE2SGNUQdia7K0GTZEKMGIUsIWTsByV2eFx9NQU5kUNpFzF0gLAUgnqivPZWHrDdRhonR0whQgFWgkUMfROQGtWG7Zn+8ET77Ax58ZF25PDa4tTZeWgZD1ybLxWsBOrYzHAd7YtDYm62N\/Oc4Kz2\/fLX9k\/octQBV2HTqOzgpBTdNsYzq3HyGDoFrI6glXIx+LqS30sxcFv6n8FWULo+lBKPK7uG03hWwwoxSeU0oFz\/\/uiV8K28rlc\/0JZBbMvvNjWuXuduxCBnzAAgX4cNHSy5D1UXhxgZEIR3\/CU50vuMwBgfE3CDTh60hSs=",
904
+    "certificate": "-----BEGIN CERTIFICATE-----\r\nMIIECTCCAvECAhG8MA0GCSqGSIb3DQEBCwUAMHsxCzAJBgNVBAYTAkRFMRswGQYD\r\nVQQIDBJCYWRlbi1XdWVydHRlbWJlcmcxFzAVBgNVBAoMDk5leHRjbG91ZCBHbWJI\r\nMTYwNAYDVQQDDC1OZXh0Y2xvdWQgQ29kZSBTaWduaW5nIEludGVybWVkaWF0ZSBB\r\ndXRob3JpdHkwHhcNMjIwMjI1MTYwMjIyWhcNMzIwNjAyMTYwMjIyWjAZMRcwFQYD\r\nVQQDDA5zbXNfcmVsZW50bGVzczCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC\r\nggIBALbJJdLJIooOqb46AyOdNlWR9LXm3hWzjNBkH0o8wtMFEnotUOLcbaXbmTun\r\niG0Q0eunZGLSF6in+kY5M420Jh9bbDP6bYI8iDG6CSDkmKgnfcdJRlB6i7g0qBG8\r\noMzOB1x7ZVTef8Ho2ylTMWCxCfTlcQ15okAUpLU1G37I5rg0DZH2fPdGs9PMg11a\r\n64Tofl2GJSf9aHsgLi0AXXVzSN\/96wmK2fJYBqTVsPo5qIqKtMVWduhDXsb9yT4q\r\nDMYzyHrr8ydrMSGPwfs940R00hG2qHJcuKKGjYCCtu7djMfpKA9fqsGZBE6IWlVH\r\nCZxYIHPaEfHOybPR5d2GIKzncUQjtO2\/9rsju31GwzrVswG7w0tQUIIaj5AFLIL3\r\njnagjo2LH11ta9mB+DikaZDfd4VYEEfkTJA4BjnNCDa9pYOaFBGGwJMBSH3eWJCZ\r\nURBtk2NBnIheFRaGWRAzUpKAc+ZYdnmuAqe3Eh1en9GNlKTMCO+mAHkFJp3z8Nai\r\n1ijEVK+PIgtrzqc48ft0r6L43Zd184JnSIscBm\/9GUb0sCf+Uv4WFBKm4c7nrWtM\r\nC1LMKqmj2OYD1fZJ65M1VrkAqh8VXNtqQI1caBGMkcs4\/\/1eo\/XomL6sEkvfa9Y2\r\n1OywnVt52ZeLHyUS2P1mvPyWZgL8AxIie82Mtp7ZWX9Q8ubbAgMBAAEwDQYJKoZI\r\nhvcNAQELBQADggEBAI6OdKpKpevWVprPZ1TzUpq5ATj2JyCZySYC71Ud8l3lAEmn\r\nuh9ok5P7ccY\/c\/9\/ePWuvGxNSHmk1+nEEWC8XNXY5OoU9+i+g7vXd6EKOsowallw\r\nvWZB2rjl6+eNC\/AVa0NE2d9C6AWZtLxiV6rVsmkNUbBS6orHq8JJ2PSJKPT0\/nfM\r\nWL+ZORuFguWazEsy9oZBlplaWNxyAgq\/L66SKXynQPe74kZeVdZ5aQluHnBKZAoh\r\n6v0c2YiaoG5Mg6tDWcx4zM8HXv39Nbg2hcAtP2j3F9EkHZaytW9nM7nTIOxZJtR\/\r\nuGJtkj5+e1NQaMYn2NDiYSZALGUQ3YkHv4OIzDY=\r\n-----END CERTIFICATE-----"
905
+}
0 906
\ No newline at end of file
1 907
new file mode 100644
... ...
@@ -0,0 +1,3193 @@
1
+/**
2
+ * @copyright 2021 Double Bastion LLC <www.doublebastion.com>
3
+ *
4
+ * @author Double Bastion LLC
5
+ *
6
+ * @license GNU AGPL version 3 or any later version
7
+ *
8
+ * This program is free software; you can redistribute it and/or
9
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
10
+ * License as published by the Free Software Foundation; either
11
+ * version 3 of the License, or any later version.
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
17
+ *
18
+ * You should have received a copy of the GNU Affero General Public
19
+ * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
+ *
21
+ */
22
+
23
+@font-face {
24
+    font-family: 'Inter';
25
+    src: url('../fonts/Inter-Bold.woff2') format('woff2'),
26
+         url('../fonts/Inter-Bold.woff') format('woff');
27
+    font-weight: 700;
28
+    font-style: normal;
29
+}
30
+@font-face {
31
+    font-family: 'Inter';
32
+    src: url('../fonts/Inter-BoldItalic.woff2') format('woff2'),
33
+         url('../fonts/Inter-BoldItalic.woff') format('woff');
34
+    font-weight: 700;
35
+    font-style: italic;
36
+}
37
+@font-face {
38
+    font-family: 'Inter';
39
+    src: url('../fonts/Inter-MediumItalic.woff2') format('woff2'),
40
+         url('../fonts/Inter-MediumItalic.woff') format('woff');
41
+    font-weight: 500;
42
+    font-style: italic;
43
+}
44
+@font-face {
45
+    font-family: 'Inter';
46
+    src: url('../fonts/Inter-SemiBold.woff2') format('woff2'),
47
+         url('../fonts/Inter-SemiBold.woff') format('woff');
48
+    font-weight: 600;
49
+    font-style: normal;
50
+}
51
+@font-face {
52
+    font-family: 'Inter';
53
+    src: url('../fonts/Inter-Regular.woff2') format('woff2'),
54
+         url('../fonts/Inter-Regular.woff') format('woff');
55
+    font-weight: 400;
56
+    font-style: normal;
57
+}
58
+@font-face {
59
+    font-family: 'Inter';
60
+    src: url('../fonts/Inter-SemiBoldItalic.woff2') format('woff2'),
61
+         url('../fonts/Inter-SemiBoldItalic.woff') format('woff');
62
+    font-weight: 600;
63
+    font-style: italic;
64
+}
65
+@font-face {
66
+    font-family: 'Inter';
67
+    src: url('../fonts/Inter-Italic.woff2') format('woff2'),
68
+         url('../fonts/Inter-Italic.woff') format('woff');
69
+    font-weight: 400;
70
+    font-style: italic;
71
+}
72
+@font-face {
73
+    font-family: 'Inter';
74
+    src: url('../fonts/Inter-Medium.woff2') format('woff2'),
75
+         url('../fonts/Inter-Medium.woff') format('woff');
76
+    font-weight: 500;
77
+    font-style: normal;
78
+}
79
+
80
+@font-face {
81
+    font-family: 'Open Sans';
82
+    src: url('../fonts/opensans-light.woff2') format('woff2'),
83
+         url('../fonts/opensans-light.woff') format('woff');
84
+    font-weight: 300;
85
+    font-style: normal;
86
+}
87
+@font-face {
88
+    font-family: 'Open Sans';
89
+    src: url('../fonts/opensans-lightitalic.woff2') format('woff2'),
90
+         url('../fonts/opensans-lightitalic.woff') format('woff');
91
+    font-weight: 300;
92
+    font-style: italic;
93
+}
94
+@font-face {
95
+    font-family: 'Open Sans';
96
+    src: url('../fonts/opensans-regular.woff2') format('woff2'),
97
+         url('../fonts/opensans-regular.woff') format('woff');
98
+    font-weight: 400;
99
+    font-style: normal;
100
+}
101
+@font-face {
102
+    font-family: 'Open Sans';
103
+    src: url('../fonts/opensans-italic.woff2') format('woff2'),
104
+         url('../fonts/opensans-italic.woff') format('woff');
105
+    font-weight: 400;
106
+    font-style: italic;
107
+}
108
+@font-face {
109
+    font-family: 'Open Sans';
110
+    src: url('../fonts/opensans-semibold.woff2') format('woff2'),
111
+         url('../fonts/opensans-semibold.woff') format('woff');
112
+    font-weight: 600;
113
+    font-style: normal;
114
+}
115
+@font-face {
116
+    font-family: 'Open Sans';
117
+    src: url('../fonts/opensans-semibolditalic.woff2') format('woff2'),
118
+         url('../fonts/opensans-semibolditalic.woff') format('woff');
119
+    font-weight: 600;
120
+    font-style: italic;
121
+}
122
+@font-face {
123
+    font-family: 'Open Sans';
124
+    src: url('../fonts/opensans-bold.woff2') format('woff2'),
125
+         url('../fonts/opensans-bold.woff') format('woff');
126
+    font-weight: 700;
127
+    font-style: normal;
128
+}
129
+@font-face {
130
+    font-family: 'Open Sans';
131
+    src: url('../fonts/opensans-bolditalic.woff2') format('woff2'),
132
+         url('../fonts/opensans-bolditalic.woff') format('woff');
133
+    font-weight: 700;
134
+    font-style: italic;
135
+}
136
+@font-face {
137
+    font-family: 'Open Sans';
138
+    src: url('../fonts/opensans-extrabold.woff2') format('woff2'),
139
+         url('../fonts/opensans-extrabold.woff') format('woff');
140
+    font-weight: 800;
141
+    font-style: normal;
142
+}
143
+@font-face {
144
+    font-family: 'Open Sans';
145
+    src: url('../fonts/opensans-extrabolditalic.woff2') format('woff2'),
146
+         url('../fonts/opensans-extrabolditalic.woff') format('woff');
147
+    font-weight: 800;
148
+    font-style: italic;
149
+}
150
+
151
+#smsrelentless_vbar {
152
+   font-family: 'Open Sans';
153
+}
154
+
155
+div > label {
156
+   position: relative;
157
+}
158
+
159
+label span {
160
+   display: inline-block;
161
+   min-width: 110px;
162
+   padding: 0px 0px 8px 0px;
163
+}
164
+
165
+select {
166
+  min-height: 25px;
167
+  box-sizing: border-box;
168
+  text-overflow: inherit;
169
+}
170
+
171
+.providerSettings {
172
+   background-color: #F7F7F7;
173
+   padding: 14px;
174
+}
175
+
176
+.providerName {
177
+   font-size: 18px;
178
+   font-weight: bold;
179
+   margin-bottom: 20px;
180
+}
181
+
182
+#smsrelentless_vbar {
183
+   padding: 18px;
184
+   color: #6d6c6c;
185
+}
186
+
187
+.smsr_textbox {
188
+   display: block;
189
+   box-sizing: content-box;
190
+   width: 70%;
191
+   font-family: 'Inter';
192
+   font-size: 15px;
193
+}
194
+
195
+.smsr_textbox[type='password'] {
196
+   font-size: 10px !important;
197
+}
198
+
199
+.smsr_textboxspec {
200
+   box-sizing: content-box;
201
+   width: 70%;
202
+   font-family: 'Inter';
203
+   font-size: 15px;
204
+}
205
+
206
+#copyToClipboardtel, #copyToClipboardnex, #copyToClipboardtwil, #copyToClipboardflow {
207
+   display: inline-block;
208
+   width: 18px;
209
+   height: 18px;
210
+   margin: 0px 0px -4px 5px;
211
+   cursor: pointer;
212
+}
213
+
214
+#copyToClipboardtel:hover, #copyToClipboardnex:hover, #copyToClipboardtwil:hover, #copyToClipboardflow:hover {
215
+   background-color: #E0E0E0;
216
+}
217
+
218
+#telapi_url, #nexapi_url, #twilapi_url, #twilapi_url_rec, #flowapi_url, #flowapi_url_rec {
219
+   display: inline-block;
220
+   box-sizing: content-box;
221
+   width: 70%;
222
+   font-family: 'Inter';
223
+   font-size: 15px !important;
224
+}
225
+
226
+#generate_tel_rcpt, #generate_tel_delrcpt, #generate_nex_rcpt, #generate_nex_delrcpt, #generate_twil_rcpt, #generate_twil_delrcpt, #generate_flow_rcpt, #generate_flow_delrcpt {
227
+   display: block;
228
+   white-space: normal;
229
+   word-wrap: break-word;
230
+}
231
+
232
+.generateUrl {
233
+   color: #161616;
234
+   background-color: #e3ecf0 !important;
235
+   font-family: 'Inter';
236
+}
237
+
238
+.generateUrl:hover {
239
+   background-color: #c2dcea !important;
240
+}
241
+
242
+.generateUrl:active {
243
+   background-color: #b5cfdd !important;
244
+}
245
+
246
+.setlabeltext {
247
+  font-size: 15px;
248
+}
249
+
250
+#smsr_save_msg {
251
+   display: inline;
252
+   color: #181918;
253
+   background-color: #a5e5b3;
254
+   font-weight: bold;
255
+}
256
+
257
+#get_notify {
258
+   display: block;
259
+   margin-bottom: 18px;
260
+   cursor: pointer;
261
+}
262
+
263
+#includesmsinemail, #showdisplaynames, #adddisplaynames, #showallmessages {
264
+   display: block;
265
+   margin-bottom: 14px;
266
+   cursor: pointer;
267
+}
268
+
269
+#currentbaldiv, #smsnumbersdiv {
270
+   display: block;
271
+   position: relative;
272
+   font-size: 15px;
273
+   font-weight: bold;
274
+   height: 30px;
275
+   margin: 0px 0px 14px 0px;
276
+   background-color: #4CA3D9;
277
+   border-radius: 20px;
278
+}
279
+
280
+.providername {
281
+  color: #FFFFFF;
282
+}
283
+
284
+.providername:hover {
285
+  color: #2c0cfc;
286
+}
287
+
288
+#currentbalance {
289
+  display: inline;
290
+  position: absolute;
291
+  margin: 3px 0px 0px 114px;
292
+  color: #262626;
293
+  font-weight: 600;
294
+}
295
+
296
+#smsprovider {
297
+  display: inline;
298
+  position: absolute;
299
+  width: 102px;
300
+  height: 22px;
301
+  margin: 3px 0px 0px 0px;
302
+  padding: 0px 0px 1px 0px !important;
303
+  -moz-box-sizing: border-box;
304
+  -webkit-box-sizing: border-box;
305
+  box-sizing: border-box;
306
+  background: #fcfcfc;
307
+  font-family: 'Inter' !important;
308
+  font-size: 14.5px;
309
+  font-weight: 600;
310
+  color: #565656;
311
+  text-align: center;
312
+  border-radius: 20px;
313
+}
314
+
315
+#currentsmsnmbrs {
316
+  display: inline-block;
317
+  position: absolute;
318
+  height: 22px;
319
+  width: 54%;
320
+  padding: 0 !important;
321
+  margin: 2px 0px 0px 0px;
322
+  text-align: center;
323
+  text-overflow: inherit;
324
+  font-family: 'Inter' !important;
325
+  font-size: 14px;
326
+  font-weight: 600;
327
+  color: #565656;
328
+  -moz-box-sizing: border-box;
329
+  -webkit-box-sizing: border-box;
330
+  box-sizing: border-box;
331
+  background: #fcfcfc;
332
+  border-radius: 20px;
333
+}
334
+
335
+#refreshSenderIDs {
336
+  display: block;
337
+  position: relative;
338
+  min-width: 24px;
339
+  min-height: 24px;
340
+  float: right;
341
+  padding-left: 0;
342
+  margin-top: 2.6px;
343
+  margin-right: 4px;
344
+  background-image: url('../img/refresh.svg');
345
+  background-repeat: no-repeat;
346
+  background-size: 110% 110%;
347
+  background-position: center center;
348
+  cursor: pointer;
349
+  background-color: #ffffff;
350
+}
351
+
352
+.cllridcls {
353
+  position: relative;
354
+  display: inline;
355
+  font-size: 17px;
356
+  color: #000000;
357
+}
358
+
359
+.tooltipbalanceid  {
360
+  position: relative;
361
+  display: inline-block;
362
+  float: right;
363
+  font-size: 15px;
364
+  color: #000000;
365
+  z-index: 9;
366
+}
367
+
368
+.tooltipsetid  {
369
+  position: relative;
370
+  display: inline-block;
371
+  float: right;
372
+  font-size: 15px;
373
+  color: #000000;
374
+  z-index: 8;
375
+}
376
+
377
+.tooltipbalanceid #infobalance {
378
+  display: block;
379
+  position: relative;
380
+  margin: 4px 14px 0px 0px;
381
+  color: #000000;
382
+  font-size: 19px;
383
+  font-weight: bold;
384
+  font-family: 'Open Sans';
385
+  font-style: italic;
386
+  z-index: 6;
387
+}
388
+
389
+.tooltipbalanceid .balancetooltip {
390
+  display: block;
391
+  position: absolute;
392
+  visibility: hidden;
393
+  width: 264px;
394
+  background-color: #fafafa;
395
+  font-size: 14px;
396
+  font-weight: bold;
397
+  color: #595959;
398
+  text-align: left;
399
+  border-radius: 5px;
400
+  padding: 5px 5px 5px 8px;
401
+  margin: -4px 0px 0px -244px;
402
+  box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
403
+  -webkit-box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
404
+  -moz-box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
405
+  z-index: 6;
406
+}
407
+
408
+.tooltipbalanceid:hover .balancetooltip {
409
+   visibility: visible;
410
+}
411
+
412
+#infotipid {
413
+   display: block;
414
+   position: relative;
415
+   margin: 3.5px 12px 0px 0px;
416
+   color: #000000;
417
+   font-size: 19px;
418
+   font-weight: bold;
419
+   font-family: 'Open Sans';
420
+   font-style: italic;
421
+   z-index: 5;
422
+}
423
+
424
+#setcalleridtp {
425
+   display: block;
426
+   position: absolute;
427
+   width: 274px;
428
+   overflow-y: scroll;
429
+   visibility: hidden;
430
+   background-color: #fafafa;
431
+   border-radius: 5px;
432
+   margin: -5px 0px 0px -223px;
433
+   scrollbar-width: auto;
434
+   scrollbar-color: #a2a2a2 #ececec;
435
+   box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
436
+   -webkit-box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
437
+   -moz-box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
438
+   z-index: 10;
439
+}
440
+
441
+.calleridtooltip {
442
+   display: block;
443
+   position: relative;
444
+   width: auto;
445
+   height: auto;
446
+   background-color: #f4f4f4;
447
+   font-size: 14px;
448
+   font-weight: bold;
449
+   color: #595959;
450
+   text-align: left;
451
+   padding: 5px 12px 5px 10px;
452
+   z-index: 10;
453
+}
454
+
455
+.tooltipsetid:hover #setcalleridtp {
456
+   visibility: visible;
457
+}
458
+
459
+.pflabels {
460
+   font-size: 15px;
461
+   font-weight: bold;
462
+}
463
+
464
+.srheader {
465
+   display: block;
466
+   position: relative;
467
+   margin: 0px 0px 7px 0px;
468
+   font-size: 15px;
469
+   font-weight: bold;
470
+}
471
+
472
+.sendtomultrcvrs {
473
+   display: block;
474
+   position: relative;
475
+   margin: 0px 0px 7px 0px;
476
+   font-size: 17px;
477
+}
478
+
479
+.smsnbformat {
480
+   display: block;
481
+   position: relative;
482
+   margin: 0px;
483
+   font-size: 15px;
484
+   font-weight: bold;
485
+}
486
+
487
+.smsrelentless_box {
488
+   width: 400px;
489
+   display: block;
490
+}
491
+.indtext {
492
+   display: inline-block;
493
+   padding-left: 10px;
494
+}
495
+
496
+#settings-dscr {
497
+   padding-top: 3px;
498
+}
499
+
500
+#sms_upload_msg {
501
+   display: block;
502
+   color: #181918;
503
+   background-color: #a5e5b3;
504
+   font-weight: bold;
505
+}
506
+
507
+#sms_submit_msg {
508
+   display: none;
509
+   margin: 14px 0px 8px 0px;
510
+   padding: 3px 20px 0px 20px;
511
+   width: 100%;
512
+   color: #181918;
513
+   background-color: #a5e5b3;
514
+   font-size: 15px;
515
+   font-weight: bold;
516
+   text-align: center;
517
+   border-radius: 14px;
518
+}
519
+
520
+#pickedfilename {
521
+   font-size: 13px;
522
+}
523
+
524
+#smstodiv {
525
+   display: block;
526
+   position: relative;
527
+   height: 32px;
528
+}
529
+
530
+#smsto {
531
+   display: block;
532
+   width: 99%;
533
+   max-height: 32px;
534
+   padding: 0px 15px 0px 15px;
535
+   color: #565656;
536
+   font-family: 'Inter';
537
+   font-size: 15px;
538
+   font-weight: 600;
539
+   border-radius: 20px;
540
+}
541
+
542
+#sendtomultiple {
543
+   display: inline-block;
544
+   position: relative;
545
+   margin: 10px 0px 12px 0px;
546
+   font-size: 15px;
547
+   font-weight: bold;
548
+}
549
+
550
+#entermessage {
551
+   display: block;
552
+   position: relative;
553
+   margin: 4px 0px 0px 0px;
554
+   font-size: 15px;
555
+   font-weight: bold;
556
+}
557
+
558
+#uploadfileforsms {
559
+   margin-left: 7px;
560
+   background-color: #ffffff;
561
+   border-radius: 3px !important;
562
+}
563
+
564
+.entertime {
565
+   display: inline;
566
+   font-size: 15px;
567
+   font-weight: bold;
568
+   margin-right: 7px;
569
+}
570
+
571
+#sendmediafl {
572
+   display: block;
573
+   position: relative;
574
+   margin: 0px 0px 20px 0px;
575
+   font-size: 15px;
576
+   font-weight: bold;
577
+}
578
+
579
+#tomultchckbx {
580
+   display: inline-block;
581
+   position: absolute;
582
+   margin: 3px 0px 0px 10px;
583
+}
584
+
585
+#mediafilechckbx {
586
+   display: inline-block;
587
+   position: absolute;
588
+   margin: -7px 0px 0px 10px;
589
+}
590
+
591
+#deleteoldchckbox {
592
+   display: inline-block;
593
+   position: absolute;
594
+   margin: 3.5px 0px 0px 10px;
595
+}
596
+
597
+#tomultchckbx:hover, #mediafilechckbx:hover, #deleteoldchckbox:hover {
598
+   cursor: pointer;
599
+}
600
+
601
+.maxmessagelength {
602
+   display: none;
603
+   position: relative;
604
+   margin: 2px 7px 4px 0px;
605
+   font-size: 15px;
606
+   color: #000000;
607
+   z-index: 6;
608
+}
609
+
610
+#maxlengthinfo {
611
+   display: block;
612
+   position: absolute;
613
+   width: 274px;
614
+   height: 200px;
615
+   overflow-y: scroll;
616
+   visibility: hidden;
617
+   background-color: #fafafa;
618
+   border-radius: 5px;
619
+   margin: -11px 0px 0px -6px;
620
+   scrollbar-width: auto;
621
+   scrollbar-color: #a2a2a2 #ececec;
622
+   box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
623
+   -webkit-box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
624
+   -moz-box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
625
+   z-index: 10;
626
+}
627
+
628
+.maxlengthtooltip {
629
+   display: block;
630
+   position: relative;
631
+   width: auto;
632
+   height: auto;
633
+   background-color: #f4f4f4;
634
+   font-size: 14px;
635
+   font-weight: bold;
636
+   color: #595959;
637
+   text-align: left;
638
+   padding: 5px 12px 5px 10px;
639
+   z-index: 10;
640
+}
641
+
642
+.maxmessagelength:hover #maxlengthinfo {
643
+   visibility: visible;
644
+}
645
+
646
+.up-bttn-wrapper {
647
+  display: block;
648
+  position: relative;
649
+  overflow: hidden;
650
+  padding-top: 20px;
651
+  padding-bottom: 30px;
652
+}
653
+
654
+#smstext {
655
+  display: inline-block;
656
+  color: #2a2a2a;
657
+  width: 100%;
658
+  height: 130px;
659
+  text-align: left;
660
+  font-family: 'Inter';
661
+  font-size: 15px;
662
+  font-weight: 500;
663
+  border-radius: 6px;
664
+  resize: vertical;
665
+  white-space: pre-wrap;
666
+}
667
+
668
+#char_count {
669
+  display: none;
670
+  font-size: 14px;
671
+  font-weight: bold;
672
+}
673
+
674
+#mtextSize {
675
+  display: none;
676
+  margin-left: 10px;
677
+  font-size: 14px;
678
+  font-weight: bold;
679
+  color: #4CA3D9;
680
+}
681
+
682
+#submitsms {
683
+   display: block;
684
+   position: relative;
685
+   margin-top: 14px;
686
+   color: white;
687
+   font-family: 'Open Sans';
688
+   font-weight: 700;
689
+   font-size: 15px;
690
+   background-color: #4CA3D9;
691
+   border-radius: 20px;
692
+   cursor: pointer;
693
+   opacity: 1 !important;
694
+}
695
+
696
+#submitsms:hover {
697
+   border-color: #5CAECC;
698
+}
699
+
700
+#submitsms:active {
701
+   background: #4B96B1;
702
+   border-color: #4B96B1;
703
+}
704
+
705
+#multiplerecivers {
706
+   display: none;
707
+   background: #e8f6ff;
708
+   border-radius: 6px;
709
+   padding: 5px;
710
+   margin: 0px 0px 20px 0px;
711
+}
712
+
713
+#multsetrows {
714
+  display: block;
715
+  padding: 5px;
716
+}
717
+
718
+#multsmsinterval {
719
+  display: block;
720
+  width: 100px;
721
+  height: 25px;
722
+  font-family: 'Inter';
723
+  font-size: 14px;
724
+  font-weight: 600;
725
+  padding: 0px 0px 0px 10px;
726
+  border-radius: 20px;
727
+}
728
+
729
+#app {
730
+  position: relative;
731
+  display: flex;
732
+  min-height: 100%;
733
+  min-width: 100%;
734
+}
735
+
736
+#app-content {
737
+   position: relative;
738
+   z-index: 1000;
739
+   flex-basis: 100vw;
740
+   min-width: 0;
741
+   min-height: 100%;
742
+   margin: 0 !important;
743
+   overflow-y: scroll;
744
+}
745
+
746
+#viewerContainer {
747
+   display: block;
748
+   position: relative;
749
+   width: 100%;
750
+   height: 100%;
751
+}
752
+
753
+.pdfViewer #viewer {
754
+   display: block;
755
+   position: relative;
756
+   min-width: 100%;
757
+   min-height: 100%;
758
+}
759
+
760
+#smsdocpreview {
761
+   display: inline-block;
762
+   position: relative;
763
+   width: 100%;
764
+   height: 100%;
765
+   margin-top: -50px;
766
+}
767
+
768
+#outerContainer {
769
+   display: block;
770
+   position: relative;
771
+   width: 100%;
772
+   height: 100%;
773
+}
774
+
775
+#mainContainer {
776
+   display: block;
777
+   position: relative;
778
+   width: 100%;
779
+   height: 100%;
780
+}
781
+
782
+.texttooltip {
783
+  font-family: 'Open Sans';
784
+  font-style: italic;
785
+  color: #000000;
786
+  font-size: 19px;
787
+  font-weight: bold;
788
+  margin: 0px 0px 4px 4px;
789
+}
790
+
791
+.fortooltip {
792
+   position: relative;
793
+   display: inline-block;
794
+   margin: 0px;
795
+   font-size: 15px;
796
+   color: #000000;
797
+   z-index: 7;
798
+}
799
+
800
+.fortooltipsec {
801
+   position: relative;
802
+   display: inline-block;
803
+   font-size: 15px;
804
+   color: #000000;
805
+   padding: 2px 0px 4px 2px;
806
+   z-index: 3;
807
+}
808
+
809
+.fortooltiptert {
810
+   position: relative;
811
+   display: inline-block;
812
+   font-size: 15px;
813
+   color: #000000;
814
+   padding: 2px 0px 4px 2px;
815
+   z-index: 0;
816
+}
817
+
818
+.fortooltipfourth {
819
+   position: relative;
820
+   display: inline-block;
821
+   font-size: 15px;
822
+   color: #000000;
823
+   padding: 2px 0px 4px 2px;
824
+   z-index: 4;
825
+}
826
+
827
+#tonmbrformat {
828
+   display: block;
829
+   position: absolute;
830
+   width: 274px;
831
+   overflow-y: scroll;
832
+   visibility: hidden;
833
+   background-color: #fafafa;
834
+   border-radius: 5px;
835
+   margin: -11px 0px 0px -6px;
836
+   scrollbar-width: auto;
837
+   scrollbar-color: #a2a2a2 #ececec;
838
+   box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
839
+   -webkit-box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
840
+   -moz-box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
841
+   z-index: 10;
842
+}
843
+
844
+.fortooltiptext {
845
+   display: block;
846
+   position: relative;
847
+   width: auto;
848
+   height: auto;
849
+   background-color: #f4f4f4;
850
+   font-size: 14px;
851
+   font-weight: bold;
852
+   color: #595959;
853
+   text-align: left;
854
+   padding: 5px 12px 5px 10px;
855
+   z-index: 10;
856
+}
857
+
858
+.fortooltip:hover #tonmbrformat {
859
+   visibility: visible;
860
+}
861
+
862
+#uploadfileinfo {
863
+   display: block;
864
+   position: absolute;
865
+   width: 274px;
866
+   overflow-y: scroll;
867
+   visibility: hidden;
868
+   background-color: #fafafa;
869
+   border-radius: 5px;
870
+   margin: -11px 0px 0px -6px;
871
+   scrollbar-width: auto;
872
+   scrollbar-color: #a2a2a2 #ececec;
873
+   box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
874
+   -webkit-box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
875
+   -moz-box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
876
+   z-index: 10;
877
+}
878
+
879
+.fortooltiptextsec {
880
+   display: block;
881
+   position: relative;
882
+   width: auto;
883
+   height: auto;
884
+   background-color: #f4f4f4;
885
+   font-size: 14px;
886
+   font-weight: bold;
887
+   color: #595959;
888
+   text-align: left;
889
+   padding: 5px 12px 5px 10px;
890
+   z-index: 10;
891
+}
892
+
893
+.fortooltipsec:hover #uploadfileinfo {
894
+   visibility: visible;
895
+}
896
+
897
+#deleteoldinfo {
898
+   display: block;
899
+   position: absolute;
900
+   width: 274px;
901
+   height: 200px;
902
+   overflow-y: scroll;
903
+   visibility: hidden;
904
+   background-color: #fafafa;
905
+   border-radius: 5px;
906
+   margin: -11px 0px 0px -6px;
907
+   scrollbar-width: auto;
908
+   scrollbar-color: #a2a2a2 #ececec;
909
+   box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
910
+   -webkit-box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
911
+   -moz-box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
912
+   z-index: 10;
913
+}
914
+
915
+.fortooltiptexttert {
916
+   display: block;
917
+   position: relative;
918
+   width: auto;
919
+   height: auto;
920
+   background-color: #f4f4f4;
921
+   font-size: 14px;
922
+   font-weight: bold;
923
+   color: #595959;
924
+   text-align: left;
925
+   padding: 5px 12px 5px 10px;
926
+   z-index: 10;
927
+}
928
+
929
+.fortooltiptert:hover #deleteoldinfo {
930
+   visibility: visible;
931
+}
932
+
933
+#uploadmmfileinfo {
934
+   display: block;
935
+   position: absolute;
936
+   width: 274px;
937
+   height: 350px;
938
+   overflow-y: scroll;
939
+   visibility: hidden;
940
+   background-color: #fafafa;
941
+   border-radius: 5px;
942
+   margin: -11px 0px 0px -16px;
943
+   scrollbar-width: auto;
944
+   scrollbar-color: #a2a2a2 #ececec;
945
+   box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
946
+   -webkit-box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
947
+   -moz-box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
948
+   z-index: 10;
949
+}
950
+
951
+#tooltiptextfourth {
952
+   display: block;
953
+   position: relative;
954
+   width: auto;
955
+   height: auto;
956
+   background-color: #f4f4f4;
957
+   font-size: 14px;
958
+   font-weight: bold;
959
+   color: #595959;
960
+   text-align: left;
961
+   padding: 5px 12px 5px 10px;
962
+   z-index: 10;
963
+}
964
+
965
+.fortooltipfourth:hover #uploadmmfileinfo {
966
+   visibility: visible;
967
+}
968
+
969
+.fileupload {
970
+   display: none;
971
+}
972
+
973
+.uploadflbt {
974
+   width: 411px;
975
+}
976
+
977
+#infotipmms {
978
+   display: block;
979
+   position: relative;
980
+   margin: 0px;
981
+   color: #000000;
982
+   font-size: 19px;
983
+   font-weight: bold;
984
+   font-family: 'Open Sans';
985
+   font-style: italic;
986
+   z-index: 5;
987
+}
988
+
989
+#mmsfoldersview {
990
+   display: none;
991
+   position: relative;
992
+   width: 100%;
993
+   height: 100%;
994
+   margin-top: -50px;
995
+   background-color: #f4f9ff;
996
+}
997
+
998
+#upmediafiles {
999
+   display: none;
1000
+   background: #e8f6ff;
1001
+   border-radius: 6px;
1002
+   padding: 10px;
1003
+   margin: 0px 0px 20px 0px;
1004
+}
1005
+
1006
+.uploadflbt .icon-upload {
1007
+   display: inline;
1008
+}
1009
+
1010
+.pfprompt {
1011
+   font-size: 15px;
1012
+   font-weight: bold;
1013
+}
1014
+
1015
+.fileuploadstl, .filesfromnc {
1016
+  display: block;
1017
+  font-size: 15px;
1018
+  font-weight: bold;
1019
+  color: #000000;
1020
+}
1021
+
1022
+#uploadfileformms {
1023
+  margin-left: 21px;
1024
+  background-color: #ffffff;
1025
+  border-radius: 3px !important;
1026
+}
1027
+
1028
+#filestotsize {
1029
+  display: none;
1030
+  position: relative;
1031
+  height: auto;
1032
+  padding: 0px 0px 8px 0px;
1033
+  font-size: 14px;
1034
+  font-weight: bold;
1035
+  color: #189558;
1036
+}
1037
+
1038
+#filessizetext {
1039
+  display: inline;
1040
+  position: relative;
1041
+  padding-left: 10px;
1042
+}
1043
+
1044
+#fileuploadednm #induploadfile .indivflcls {
1045
+  display: inline-block;
1046
+  position: relative;
1047
+  height:auto;
1048
+  max-width: 90%;
1049
+  overflow: visible;
1050
+  white-space: normal;
1051
+  word-break: break-all;
1052
+  text-overflow: ellipsis;
1053
+  font-size: 15px;
1054
+  color: #0e6ba0;
1055
+}
1056
+
1057
+#fileuploadednm #induploadfile .indivflcls:hover {
1058
+  cursor: pointer;
1059
+  text-decoration: underline;
1060
+}
1061
+
1062
+#fileuploadednm #induploadfile .indupfldl {
1063
+  position: relative;
1064
+  display: inline-block;
1065
+  float: right;
1066
+  cursor: pointer;
1067
+  width: 20px;
1068
+  color: #0e6ba0;
1069
+  text-align: center;
1070
+  font-size: 15px;
1071
+}
1072
+
1073
+#fileuploadednm #induploadfile .indupfldl:hover {
1074
+  background-color: #e8f6ff;
1075
+  cursor: pointer;
1076
+}
1077
+
1078
+#filespickednc .indivflpckd {
1079
+  display: inline-block;
1080
+  position: relative;
1081
+  height:auto;
1082
+  max-width: 90%;
1083
+  overflow: visible;
1084
+  white-space: normal;
1085
+  word-break: break-all;
1086
+  text-overflow: ellipsis;
1087
+  color: #0e6ba0;
1088
+}
1089
+
1090
+.indivflpckd:hover {
1091
+  cursor: pointer;
1092
+  text-decoration: underline;
1093
+}
1094
+
1095
+.indpckfldl {
1096
+  position: relative;
1097
+  display: inline-block;
1098
+  float: right;
1099
+  cursor: pointer;
1100
+  width: 20px;
1101
+  color: #0e6ba0;
1102
+  text-align: center;
1103
+}
1104
+
1105
+#filespickednc .indpckfldl:hover {
1106
+  background-color: #e8f6ff;
1107
+  cursor: pointer;
1108
+}
1109
+
1110
+#pf_upload_msg, #pf_choose_msg {
1111
+  display: block;
1112
+  color: #181918;
1113
+  background-color: #a5e5b3;
1114
+  font-weight: bold;
1115
+  text-align: center;
1116
+  border-radius: 3px;
1117
+}
1118
+
1119
+#choosefilen {
1120
+  display: inline;
1121
+  position: relative;
1122
+  margin: 0px 0px 20px 16px;
1123
+  padding-top: 15px;
1124
+  background-image: url('../img/nextcloud_logo.svg');
1125
+  background-repeat: no-repeat;
1126
+  background-size: 110% 125%;
1127
+  background-position: center center;
1128
+  min-width: 66px;
1129
+  min-height: 30px;
1130
+  cursor:pointer;
1131
+}
1132
+
1133
+#choosefilen:active {
1134
+  background-image: url('../img/nextcloud_logo_bright.svg');
1135
+  background-repeat: no-repeat;
1136
+  background-size: 110% 125%;
1137
+  background-position: center center;
1138
+  min-width: 66px;
1139
+  min-height: 30px;
1140
+}
1141
+
1142
+#pickFromNext, #uploadFile {
1143
+  display: inline-block;
1144
+  position: relative;
1145
+  font-size: 15px;
1146
+  font-weight: bold;
1147
+  color: #6d6c6c;
1148
+}
1149
+
1150
+#filespickednc .indivflpckd {
1151
+  display: inline-block;
1152
+  position: relative;
1153
+  height:auto;
1154
+  max-width: 90%;
1155
+  overflow: visible;
1156
+  white-space: normal;
1157
+  word-break: break-all;
1158
+  text-overflow: ellipsis;
1159
+  color: #0e6ba0;
1160
+}
1161
+
1162
+#filespickednc .indpckfldl:hover {
1163
+  background-color: #e8f6ff;
1164
+  cursor: pointer;
1165
+}
1166
+
1167
+.uploadflbt {
1168
+  width: 411px;
1169
+}
1170
+
1171
+.uploadflbt .icon-upload {
1172
+  display: inline;
1173
+}
1174
+
1175
+.uploadfiledv {
1176
+  display: inline-block;
1177
+  position: relative;
1178
+  margin: 16px 0px 22px 0px;
1179
+}
1180
+
1181
+#mmsfileuploadednm .indivflcls {
1182
+  display: inline-block;
1183
+  position: relative;
1184
+  height:auto;
1185
+  max-width: 90%;
1186
+  overflow: visible;
1187
+  white-space: normal;
1188
+  word-break: break-all;
1189
+  text-overflow: ellipsis;
1190
+  color: #0e6ba0;
1191
+}
1192
+
1193
+#mmsfileuploadednm .indivflcls:hover {
1194
+  cursor: pointer;
1195
+  text-decoration: underline;
1196
+}
1197
+
1198
+#mmsfileuploadednm .indupfldl {
1199
+  position: relative;
1200
+  display: inline-block;
1201
+  float: right;
1202
+  cursor: pointer;
1203
+  width: 20px;
1204
+  color: #0e6ba0;
1205
+  text-align: center;
1206
+}
1207
+
1208
+#mmsfileuploadednm .indupfldl:hover {
1209
+  background-color: #e8f6ff;
1210
+  cursor: pointer;
1211
+}
1212
+
1213
+#filessizetext {
1214
+  display: inline;
1215
+  position: relative;
1216
+  padding-left: 10px;
1217
+}
1218
+
1219
+.srheaderch {
1220
+  display: block;
1221
+  position: relative;
1222
+  margin: 0px 0px 15px 0px;
1223
+  font-size: 15px;
1224
+  font-weight: bold;
1225
+}
1226
+
1227
+.indgenflclsmms, .indgenpckfls {
1228
+  display: block;
1229
+  margin: 10px 6px 0px 6px;
1230
+}
1231
+
1232
+#pickfilesNext {
1233
+  display: block;
1234
+  margin: 20px 0px 0px 0px;
1235
+}
1236
+
1237
+#dirbuttons {
1238
+  margin-top: 20px;
1239
+}
1240
+
1241
+button, input, textarea, div[contenteditable="true"], div[contenteditable="false"] {
1242
+  min-height: 9px;
1243
+}
1244
+
1245
+#choosefilen {
1246
+  display: inline;
1247
+  position: relative;
1248
+  margin: 4px 0px 20px 16px;
1249
+  background-image: url('../img/nextcloud_logo.svg');
1250
+  background-repeat: no-repeat;
1251
+  background-size: 110% 125%;
1252
+  background-position: center center;
1253
+  min-width: 66px;
1254
+  min-height: 30px;
1255
+  cursor:pointer;
1256
+}
1257
+
1258
+#choosefilen:active {
1259
+  background-image: url('../img/nextcloud_logo_bright.svg');
1260
+  background-repeat: no-repeat;
1261
+  background-size: 110% 125%;
1262
+  background-position: center center;
1263
+  min-width: 66px;
1264
+  min-height: 30px;
1265
+}
1266
+
1267
+#pickid, #showsum {
1268
+  display: inline-block;
1269
+  position: relative;
1270
+  font-size: 15px;
1271
+  font-weight: bold;
1272
+  margin: 3px 4px 0px 14px;
1273
+  color: #FFFFFF;
1274
+}
1275
+
1276
+.smsrelentless_checkbox:hover {
1277
+  cursor: pointer;
1278
+}
1279
+
1280
+#smstables {
1281
+  display: block; 
1282
+  position: relative;
1283
+  min-width: 100%;
1284
+  min-height: 100%;
1285
+  font-family: 'Inter' !important;
1286
+}
1287
+
1288
+#smsRGreyLogo {
1289
+  display: block;
1290
+  position: relative;
1291
+  background-image: url('../img/sms_relentless_grey.svg');
1292
+  background-repeat: no-repeat;
1293
+  background-position: center center;
1294
+  width: 100%;
1295
+  height: 675px;
1296
+}
1297
+
1298
+#recSmsTable, #sentSmsTable {
1299
+  display: block;
1300
+  position: relative;
1301
+  top: 0px;
1302
+  width: 100%;
1303
+  height: auto;
1304
+  font-size: 14px;
1305
+  z-index: 50;
1306
+  background: #FFFFFF;
1307
+}
1308
+
1309
+.receivedrows, .receivedrowsbody, .sentrows, .sentrowsbody, .groupedmsgrows {
1310
+  border: 1px solid #f3f3f3;
1311
+  padding: 8px;
1312
+}
1313
+
1314
+#groupedSmsTable {
1315
+  display: block;
1316
+  position: relative;
1317
+  top: 0px;
1318
+  width: 100%;
1319
+  height: auto;
1320
+  font-size: 14px;
1321
+  z-index: 50;
1322
+  background: #FFFFFF;
1323
+}
1324
+
1325
+#groupedSmsTable td {
1326
+  text-align: left;
1327
+  vertical-align: top;
1328
+  border: 1px solid #f3f3f3;
1329
+  padding: 5px;
1330
+}
1331
+
1332
+.groupedrowsbody {
1333
+  border: 1px solid #f3f3f3;
1334
+  padding: 8px;
1335
+}
1336
+
1337
+.groupedLstNmbr {
1338
+  overflow: scroll;
1339
+  white-space: nowrap;
1340
+}
1341
+
1342
+.groupedLstNames {
1343
+  overflow: scroll;
1344
+  white-space: nowrap;
1345
+}
1346
+
1347
+.groupedLstMsgs {
1348
+  overflow: scroll;
1349
+  white-space: nowrap;
1350
+}
1351
+
1352
+.groupedSentMsg {
1353
+  display: block;
1354
+  width: 95%;
1355
+  float: right;
1356
+  margin: 6px 6px 6px 0px;
1357
+  padding: 8px 10px;
1358
+  border: 0;
1359
+  border-radius: 10px;
1360
+  background-color: #f2fbff;
1361
+  font-size: 14px;
1362
+  white-space: normal;
1363
+  word-break: break-word;
1364
+}
1365
+
1366
+.groupedRecMsg {
1367
+  display: block; 
1368
+  width: 95%;
1369
+  float: left;
1370
+  margin: 6px 0px;
1371
+  padding: 8px 10px;
1372
+  border: 0;
1373
+  border-radius: 10px;
1374
+  background-color: #f2fff8;
1375
+  font-size: 14px;
1376
+  white-space: normal;
1377
+  word-break: break-word;
1378
+}
1379
+
1380
+.fixedRowHeight {
1381
+  max-height: 300px;
1382
+}
1383
+
1384
+.expandGrpRow {
1385
+  display: block;
1386
+  margin:-3px auto 7px auto;
1387
+  cursor: pointer;
1388
+}
1389
+
1390
+.dispNameList {
1391
+  display: block;
1392
+  margin: 2px 0px;
1393
+  font-size: 14.5px;
1394
+  font-weight: 500;
1395
+  color: #0a559e;
1396
+  cursor: pointer;
1397
+}
1398
+
1399
+.dispNameList:hover {
1400
+  color: #1483f0;
1401
+}
1402
+
1403
+.phoneNmbrRow {
1404
+  font-size: 14.5px;
1405
+  font-weight: 500;
1406
+  color: #06866f;
1407
+  cursor: pointer;
1408
+}
1409
+
1410
+.phoneNmbrRow:hover {
1411
+  color: #08b899;
1412
+}
1413
+
1414
+#selectListedNmbrs {
1415
+  display: block;
1416
+  width: 100%;
1417
+  font-family: 'Inter';
1418
+}
1419
+
1420
+.sentMssgStatus {
1421
+  display: inline-block;
1422
+  margin: 0px 6px 0px 6.5px;
1423
+}
1424
+
1425
+.saveRestrictions, .saveAutoReply {
1426
+  display: inline-block;
1427
+  border-radius: 8px !important;
1428
+  padding: 0px 14px !important;
1429
+  margin: 0px 0px 0px 10px !important;
1430
+  color: #ffffff !important;
1431
+  background-color: #59d0b4 !important;
1432
+}
1433
+
1434
+.savealwdKeys {
1435
+  display: inline-block;
1436
+  border-radius: 8px !important;
1437
+  padding: 0px 14px !important;
1438
+  margin: 0 !important;
1439
+  color: #ffffff !important;
1440
+  background-color: #59d0b4 !important;
1441
+}
1442
+
1443
+.saveRestrictions:hover, .saveAutoReply:hover, .savealwdKeys:hover {
1444
+  background-color: #40c1a3 !important;
1445
+}
1446
+
1447
+.saveRestrictions:active, .saveAutoReply:active, .savealwdKeys:active {
1448
+  background-color: #3aad92 !important;
1449
+}
1450
+
1451
+#save_admin_settings {
1452
+  display: inline-block;
1453
+  border-radius: 8px !important;
1454
+  padding: 0px 14px !important;
1455
+  color: #ffffff !important;
1456
+  background-color: #1e89c2 !important;
1457
+}
1458
+
1459
+#save_admin_settings:hover {
1460
+  background-color: #0369a0  !important;
1461
+}
1462
+
1463
+#save_admin_settings:active {
1464
+  background-color: #025480  !important;
1465
+}
1466
+
1467
+#phoneNmbrRestr th {
1468
+  font-weight: 500;
1469
+}
1470
+
1471
+#tnxKeysAccessTbl th, #plvKeysAccessTbl th, #twlKeysAccessTbl th, #flrKeysAccessTbl th {
1472
+  font-weight: 500;
1473
+  color: #222222;
1474
+}
1475
+
1476
+.restrAuthor {
1477
+  width: 200px;
1478
+  height: 40px !important;
1479
+}
1480
+
1481
+.restrPhoneNmbr, .arplPhoneNmbr {
1482
+  width: 194px;
1483
+  height: 40px !important;
1484
+}
1485
+
1486
+.restrGroups, .restrUsers {
1487
+  width: 330px;
1488
+  height: 40px !important;
1489
+  border: 1px solid #000;
1490
+  border-radius: 6px;
1491
+  margin: 0px 1px 0px 0px;
1492
+  padding: 0px 4px;
1493
+  overflow: hidden;
1494
+}
1495
+
1496
+.restrGroups:hover, .restrUsers:hover {
1497
+  overflow: auto !important;
1498
+}
1499
+
1500
+.alwdKeysGroups, .alwdKeysUsers {
1501
+  width: 398px;
1502
+  min-height: 80px !important;
1503
+  background-color: #ffffff !important;
1504
+  border: 1px solid #000;
1505
+  border-radius: 6px;
1506
+  margin: 0px 1px 0px 0px;
1507
+  padding: 0px 4px;
1508
+  overflow-y: scroll;
1509
+  white-space: pre-wrap;
1510
+}
1511
+
1512
+.alwdKeysGroups:hover, .alwdKeysUsers:hover {
1513
+  overflow: auto !important;
1514
+}
1515
+
1516
+#addRestrRow, #addArplRow {
1517
+  display: block;
1518
+  margin: 10px 0px 0px 6px;
1519
+  width: 16px;
1520
+  height: 16px;
1521
+  cursor: pointer;
1522
+  border-radius: 2px;
1523
+}
1524
+
1525
+#autoReplyTbl td {
1526
+  text-align: left;
1527
+  vertical-align: top;
1528
+  padding: 0px 0px 10px 0px;
1529
+}
1530
+
1531
+#autoReplyTbl th {
1532
+  font-weight: 500;
1533
+}
1534
+
1535
+.arplAuthor {
1536
+  width: 200px;
1537
+  height: 38px !important;
1538
+}
1539
+
1540
+.arplMode {
1541
+  display: inline-block;
1542
+  width: 330px;
1543
+  height: 184px;
1544
+  border: 1px solid #000;
1545
+  border-radius: 6px;
1546
+  margin: 0px 4px 0px 0px;
1547
+  overflow: visible;
1548
+}
1549
+
1550
+.modeContent .date-picker-x {
1551
+  top: -170px !important;
1552
+  left: -170px !important;
1553
+}
1554
+
1555
+.arplText {
1556
+  display: inline-block;
1557
+  color: #000000;
1558
+  width: 330px;
1559
+  height: 184px;
1560
+  font-size: 15px;
1561
+  text-align: left;
1562
+  border: 1px solid #000;
1563
+  border-radius: 6px;
1564
+  margin: 0px 1px 0px 0px;
1565
+  resize: vertical;
1566
+  white-space: pre-wrap;
1567
+  overflow: auto;
1568
+}
1569
+
1570
+.selectArplMode {
1571
+  display: block;
1572
+  width: 322px;
1573
+  margin: 4px 0px 0px 4px;
1574
+  cursor: pointer;
1575
+  font-weight: 500;
1576
+}
1577
+
1578
+.daysOfWeek {
1579
+  display: block;
1580
+  width: 100%;
1581
+  height: 26px;
1582
+  margin: 3px auto;
1583
+  font-weight: 500;
1584
+  text-align: center;
1585
+}
1586
+
1587
+.daysInWeek {
1588
+  display: block;
1589
+  position: relative;
1590
+  width: 322px;
1591
+  height: auto;
1592
+  margin: 0px 0px 0px 4px !important;
1593
+  text-align: center;
1594
+  border: 1px solid #000;
1595
+  border-radius: 6px;
1596
+}
1597
+
1598
+.chooseTInterval {
1599
+  display: block;
1600
+  width: 100%;
1601
+  height: 26px;
1602
+  margin: 5px auto 0px auto;
1603
+  font-weight: 500;
1604
+  text-align: center;
1605
+}
1606
+
1607
+.selectArplHours {
1608
+  display: block;
1609
+  width: 100%;
1610
+  text-align: center;
1611
+}
1612
+
1613
+.tooltipautoreply {
1614
+  display: inline-block;
1615
+  position: absolute;
1616
+  font-size: 15px;
1617
+  z-index: 9;
1618
+}
1619
+
1620
+.tooltipautoreplyst, .tooltipautoreplypn, .tooltiprestrict {
1621
+  display: inline-block;
1622
+  position: absolute;
1623
+  font-size: 15px;
1624
+  z-index: 7;
1625
+}
1626
+
1627
+#infoautoreply, #infoautoreplyst, #infoautoreplypn, #inforestrict {
1628
+  display: inline-block;
1629
+  position: relative;
1630
+  margin: -2px 0px 0px 10px;
1631
+  color: #000000;
1632
+  font-size: 18px;
1633
+  font-weight: bold;
1634
+  font-family: 'Open Sans';
1635
+  font-style: italic;
1636
+  cursor: pointer;
1637
+}
1638
+
1639
+.autorpltooltip, .autorpltooltipst, .autorpltooltippn, .restricttooltext {
1640
+  display: block;
1641
+  position: absolute;
1642
+  visibility: hidden;
1643
+  width: 330px;
1644
+  height: auto;
1645
+  background-color: #fafafa;
1646
+  font-size: 15px;
1647
+  font-weight: 600;
1648
+  white-space: normal;
1649
+  color: #595959;
1650
+  text-align: left;
1651
+  border-radius: 5px;
1652
+  padding: 5px 5px 5px 8px;
1653
+  margin: -4px 0px 0px -150px;
1654
+  box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
1655
+  -webkit-box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
1656
+  -moz-box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
1657
+}
1658
+
1659
+.tooltipautoreply:hover .autorpltooltip, .tooltipautoreplyst:hover .autorpltooltipst, .tooltipautoreplypn:hover .autorpltooltippn, .tooltiprestrict:hover .restricttooltext  {
1660
+   visibility: visible;
1661
+}
1662
+
1663
+.selectHrMin {
1664
+  font-weight: 500 !important;
1665
+  color: #01446d !important;
1666
+}
1667
+
1668
+.chooseDateIntvl {
1669
+  display: block;
1670
+  width: 100%;
1671
+  height: 32px;
1672
+  margin: 19px auto 4px auto;
1673
+  font-weight: 500;
1674
+  text-align: center;
1675
+}
1676
+
1677
+.arplstrtendDates {
1678
+  display: block;
1679
+  position: absolute;
1680
+  width: 330px;
1681
+  height: auto;
1682
+}
1683
+
1684
+.stdtTitle {
1685
+  display: inline-block;
1686
+  position: absolute;
1687
+  width: 140px;
1688
+  height: 38px;
1689
+  left: 10px;
1690
+  top: 2px;
1691
+  font-weight: 500;
1692
+  text-align: center;
1693
+}
1694
+
1695
+.enddtTitle {
1696
+  display: inline-block;
1697
+  position: absolute;
1698
+  width: 140px;
1699
+  height: 38px;
1700
+  right: 10px;
1701
+  top: 2px;
1702
+  font-weight: 500;
1703
+  text-align: center;
1704
+}
1705
+
1706
+.startDate {
1707
+  display: inline-block;
1708
+  position: absolute;
1709
+  width: 140px;
1710
+  height: 38px;
1711
+  left: 10px;
1712
+  top: 26px;
1713
+  border: 1px solid #3b3b3b;
1714
+  border-radius: 6px;
1715
+  text-align: center;
1716
+  font-weight: 500;
1717
+  color: #01446d !important;
1718
+}
1719
+
1720
+.endDate {
1721
+  display: inline-block;
1722
+  position: absolute;
1723
+  width: 140px;
1724
+  height: 38px;
1725
+  right: 10px;
1726
+  top: 26px;
1727
+  border: 1px solid #3b3b3b;
1728
+  border-radius: 6px;
1729
+  text-align: center;
1730
+  font-weight: 500;
1731
+  color: #01446d !important;
1732
+}
1733
+
1734
+#adminOverlay {
1735
+  display: block;
1736
+  position: absolute;
1737
+  top: 0;
1738
+  left: 0;
1739
+  opacity: 0;
1740
+  z-index: 4990;
1741
+}
1742
+
1743
+.grpsList, .usrsList {
1744
+  display: block;
1745
+  position: absolute;
1746
+  width: 300px;
1747
+  max-height: 400px;
1748
+  z-index: 5000;
1749
+  overflow: auto;
1750
+  background-color: #ffffff;
1751
+}
1752
+
1753
+.groupsList, .usersList {
1754
+  display: block;
1755
+  position: relative;
1756
+  float: left;
1757
+  padding: 6px 4px;
1758
+  width: 300px;
1759
+  height: auto;
1760
+  color: #353535;
1761
+  border-radius: 6px;
1762
+  border: 1px solid #dadada;
1763
+  cursor: pointer;
1764
+}
1765
+
1766
+.groupsList:hover, .usersList:hover {
1767
+  background-color: #f1f1f1;
1768
+}
1769
+
1770
+.selectedGrps, .selectedUsrs {
1771
+  display: inline-block;
1772
+  position: relative;
1773
+  margin: 6px 1px 0px 1px;
1774
+  padding: 0px 6px;
1775
+  color: #353535;
1776
+  background-color: #ffffff;
1777
+  border: 1px solid #dadada;
1778
+  border-radius: 6px;
1779
+  box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
1780
+  -webkit-box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
1781
+  -moz-box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
1782
+}
1783
+
1784
+.removeGroup, .removeUser {
1785
+  margin: 0px 0px 0px 6px;
1786
+  width: 9px;
1787
+  height: 9px;
1788
+  cursor: pointer;
1789
+}
1790
+
1791
+.showAllGroups, .showAllUsers {
1792
+  max-width: 40px !important;
1793
+  margin: 3px 10px 0px 6px;
1794
+  background-color: #ffffff;
1795
+  border-radius: 6px;
1796
+  padding: 4px 4px 0px 4px;
1797
+  z-index: 5000;
1798
+}
1799
+
1800
+.showAllGroupsak {
1801
+  max-width: 40px !important;
1802
+  margin: 3px 12px 0px 6px;
1803
+  background-color: #F7F7F7;
1804
+  border-radius: 6px;
1805
+  padding: 4px 4px 0px 4px;
1806
+}
1807
+
1808
+.showAllUsersak {
1809
+  max-width: 40px !important;
1810
+  margin: 3px 10px 0px 6px;
1811
+  background-color: #F7F7F7;
1812
+  border-radius: 6px;
1813
+  padding: 4px 4px 0px 4px;
1814
+}
1815
+
1816
+.showByNmbrTitle {
1817
+  display: block;
1818
+  width: 100%;
1819
+  color: #353535;
1820
+  text-align: center;
1821
+  font-size: 16px; 
1822
+  font-weight: 500;
1823
+  margin: 0px auto 5px auto;
1824
+}
1825
+
1826
+#refreshMsgsWrap, #refreshMsgsWraptf {
1827
+  display: block;
1828
+  position: sticky;
1829
+  width: 21px;
1830
+  height: 21px;
1831
+  bottom: 12px;
1832
+  left: 0;
1833
+}
1834
+
1835
+#refreshMsgsConv, #refreshMsgsConvtf {
1836
+  display: inline-block;
1837
+  position: relative;
1838
+  background-image: url("../img/refresh.svg");
1839
+  background-repeat: no-repeat;
1840
+  background-color: transparent !important;
1841
+  width: 21px;
1842
+  height: 21px;
1843
+  opacity: 0.30;
1844
+  border: none;
1845
+  cursor: pointer;
1846
+  z-index: 5300;
1847
+}
1848
+
1849
+#refreshMsgsConv:hover, #refreshMsgsConvtf:hover {
1850
+  opacity: 1;
1851
+}
1852
+
1853
+@media (max-width: 1020px) {
1854
+  #stopAutoRefreshSent {
1855
+    display: none;
1856
+    position: fixed;
1857
+    left: 86px;
1858
+    top: 50.7px;
1859
+    z-index: 5000;
1860
+  }
1861
+}
1862
+
1863
+@media (min-width: 1021px) {
1864
+  #stopAutoRefreshSent {
1865
+    display: none;
1866
+    position: fixed;
1867
+    left: 340px;
1868
+    top: 50.7px;
1869
+    z-index: 5000;
1870
+  }
1871
+}
1872
+
1873
+#stopAutoRefreshSentBtn {
1874
+  display: inline-block;
1875
+  position: relative;
1876
+  width: auto;
1877
+  height: auto;
1878
+  vertical-align: top;
1879
+  border: 1px solid #c6cedb;
1880
+  border-radius: 20px;
1881
+  color: #0a559e;
1882
+  font-family: 'Open Sans' !important;
1883
+  font-size: 12px;
1884
+  font-weight: 400;
1885
+  padding: 0px 9px;
1886
+  text-align: center;
1887
+  cursor: pointer;
1888
+}
1889
+
1890
+#stopAutoRefreshSentBtn:hover {
1891
+  border: 1px solid #79a2be;
1892
+  box-shadow: 0 0 6px rgba(0, 0, 0, 0.23);
1893
+  -webkit-box-shadow: 0 0 6px rgba(0, 0, 0, 0.23);
1894
+  -moz-box-shadow: 0 0 6px rgba(0, 0, 0, 0.23);
1895
+}
1896
+
1897
+.mmstblUrls {
1898
+  color: #09579b;
1899
+  cursor: pointer;
1900
+}
1901
+
1902
+.mmstblUrls:hover {
1903
+  color: #1479d3;
1904
+}
1905
+
1906
+.marksent {
1907
+  background-color: #F2FBFF !important;
1908
+}
1909
+
1910
+.markreceived {
1911
+  background-color: #F2FFF5 !important;
1912
+}
1913
+
1914
+#sentfiltersrow, #recfiltersrow, #grpfiltersrow {
1915
+  display: none;
1916
+  position: sticky;
1917
+  top: 27px;
1918
+  background: #FFFFFF;
1919
+  box-shadow: 0 6px 7px rgba(0, 0, 0, 0.1);
1920
+  z-index: 1000;
1921
+}
1922
+
1923
+#sentSmsTable th, #recSmsTable th, #groupedSmsTable th {
1924
+  position: sticky;
1925
+  top: 27px;
1926
+  z-index: 999;
1927
+  border: 1px solid #f3f3f3;
1928
+  padding: 7px;
1929
+  background-color: #bfe5f2;
1930
+  font-size: 15px;
1931
+  font-weight: bold;
1932
+  text-align: center;
1933
+}
1934
+
1935
+#sentSmsTable td, #recSmsTable td {
1936
+  border: 1px solid #f3f3f3;
1937
+  padding: 5px;
1938
+  white-space: normal;
1939
+}
1940
+
1941
+.datecolsent {
1942
+  text-align: center;
1943
+}
1944
+
1945
+.sentdbidcolumn {
1946
+  text-align: center;
1947
+}
1948
+
1949
+.dbidcolumnrec {
1950
+  width: 50px;
1951
+  text-align: center;
1952
+}
1953
+
1954
+.messagecolumnsent {
1955
+  background: #fffff2;
1956
+  text-align: left;
1957
+  font-weight: 500;
1958
+  width: 250px;
1959
+  word-break: break-word;
1960
+}
1961
+
1962
+.messagecolumnrec {
1963
+  background: #fffff2;
1964
+  text-align: left;
1965
+  font-weight: 500;
1966
+  width: 526px;
1967
+  word-break: break-word;
1968
+}
1969
+
1970
+.messageAuthorName {
1971
+  border: 0px;
1972
+  border-radius: 20px;
1973
+  padding: 4px 10px;
1974
+  margin: 0px 4px 0px 0px;
1975
+  color: #414141;
1976
+  background-color: #eff9ff;
1977
+}
1978
+
1979
+.msgAuthorNameGrp {
1980
+  border: 0px;
1981
+  border-radius: 20px;
1982
+  padding: 3px 8px;
1983
+  margin: 0px 4px 0px 0px;
1984
+  color: #616161;
1985
+  background-color: #e8edff !important;
1986
+}
1987
+
1988
+.addNameToPhNb {
1989
+  cursor: pointer;
1990
+  border-radius: 20px;
1991
+}
1992
+
1993
+.listToFromMsgs {
1994
+  display: block;
1995
+  margin: 0 auto;
1996
+  width: 30px;
1997
+  text-align: center;
1998
+  cursor: pointer;
1999
+}
2000
+
2001
+.lstMsgConv {
2002
+  display: block;
2003
+  position: relative;
2004
+  width: 30px;
2005
+  height: auto;
2006
+  text-align: center;
2007
+  margin: 4px auto 0 auto;
2008
+}
2009
+
2010
+.lstMsgConvImg {
2011
+  cursor: pointer;
2012
+  height: auto;
2013
+}
2014
+
2015
+.lstMsgToFromImg {
2016
+  cursor: pointer;
2017
+  height: auto;
2018
+}
2019
+
2020
+.lstMsgToFromImg:hover, .lstMsgConvImg:hover {
2021
+   box-shadow: 0 0 7px rgba(0, 0, 0, 0.25);
2022
+   -webkit-box-shadow: 0 0 7px rgba(0, 0, 0, 0.25);
2023
+   -moz-box-shadow: 0 0 7px rgba(0, 0, 0, 0.25);
2024
+}
2025
+
2026
+.lstMsgToFromImg:active, .lstMsgConvImg:hover {
2027
+   box-shadow: 0 0 9px rgba(0, 0, 0, 0.25);
2028
+   -webkit-box-shadow: 0 0 9px rgba(0, 0, 0, 0.25);
2029
+   -moz-box-shadow: 0 0 9px rgba(0, 0, 0, 0.25);
2030
+}
2031
+
2032
+
2033
+#loadMoreMsgs, #loadMoreMsgsusr {
2034
+  display: none;
2035
+  width: 180px;
2036
+  height: auto;
2037
+  margin: 1px auto 2px auto;
2038
+  padding: 0px 0px 2px 0px;
2039
+  border: 1px solid #b8d4e6;
2040
+  border-radius: 20px;
2041
+  color: #6c91b2;
2042
+  line-height: normal;
2043
+  text-align: center;
2044
+  font-size: 14.5px;
2045
+  font-weight: 500;
2046
+  cursor: pointer;
2047
+}
2048
+
2049
+#loadMoreMsgs:hover, #loadMoreMsgsusr:hover {
2050
+  color: #3a6c9a;
2051
+  border: 1px solid #95bad3;
2052
+}
2053
+
2054
+#loadMoreMsgs:active, #loadMoreMsgsusr:active {
2055
+  box-shadow: 0 0 6px rgba(0, 0, 0, 0.23);
2056
+  -webkit-box-shadow: 0 0 6px rgba(0, 0, 0, 0.23);
2057
+  -moz-box-shadow: 0 0 6px rgba(0, 0, 0, 0.23);
2058
+  border: 1px solid #79a2be;
2059
+}
2060
+
2061
+.addNameToPhNb:hover {
2062
+  box-shadow: 0 0 8px rgba(0, 0, 0, 0.23);
2063
+  -webkit-box-shadow: 0 0 8px rgba(0, 0, 0, 0.23);
2064
+  -moz-box-shadow: 0 0 8px rgba(0, 0, 0, 0.23);
2065
+}
2066
+
2067
+.addNameToPhNb:active {
2068
+  box-shadow: 0 0 12px rgba(0, 0, 0, 0.33);
2069
+  -webkit-box-shadow: 0 0 12px rgba(0, 0, 0, 0.33);
2070
+  -moz-box-shadow: 0 0 12px rgba(0, 0, 0, 0.33);
2071
+}
2072
+
2073
+#recTblOverlay, #alertMsgOverlay {
2074
+  display: block;
2075
+  position: absolute;
2076
+  top: 0;
2077
+  left: 0;
2078
+  width: 100%;
2079
+  height: 100%;
2080
+  background-color: #000000;
2081
+  opacity: 0.09;
2082
+  z-index: 5050;
2083
+}
2084
+
2085
+#disNameWindow, #alertMessage, #alertConfMessage {
2086
+  display: block;
2087
+  position: absolute;
2088
+  width: 338px;
2089
+  height: auto;
2090
+  white-space: pre-wrap;
2091
+  border-radius: 6px;
2092
+  background-color: #ffffff;
2093
+  box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
2094
+   -webkit-box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
2095
+   -moz-box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
2096
+  z-index: 5100;
2097
+}
2098
+
2099
+#alertTextWrap {
2100
+  display: block;
2101
+  text-align: left;
2102
+  font-family: 'Inter';
2103
+  font-size: 15px;
2104
+  margin: 30px 22px 16px 22px;
2105
+  color: #353535;
2106
+  white-space: pre-wrap;
2107
+  word-break: break-word;
2108
+}
2109
+
2110
+#closeDisNmWindow {
2111
+  display: block;
2112
+  position: absolute;
2113
+  width: 12px;
2114
+  height: 12px;
2115
+  right: 8px;
2116
+  top: 10px;
2117
+  padding: 0;
2118
+  background-image: url('../img/closewnd.svg');
2119
+  background-repeat: no-repeat;
2120
+  background-position: center center;
2121
+  cursor: pointer;
2122
+}
2123
+
2124
+#closeFrmMsgWindow, #closeAlertWnd, #closeAlertWndcf {
2125
+  display: block;
2126
+  position: absolute;
2127
+  width: 12px;
2128
+  height: 12px;
2129
+  right: 8px;
2130
+  top: 10px;
2131
+  padding: 0;
2132
+  background-image: url('../img/closewnd.svg');
2133
+  background-repeat: no-repeat;
2134
+  background-position: center center;
2135
+  cursor: pointer;
2136
+}
2137
+
2138
+#sendMsgConvBtn {
2139
+  display: flex;
2140
+  width: 200px;
2141
+  height: 20px;
2142
+  padding: 0;
2143
+  margin: -2px auto 0 auto;
2144
+  color: #ffffff;
2145
+  background: #40c1a3;
2146
+  border: 1px solid #40c1a3;
2147
+  border-radius: 20px;
2148
+  text-align: center;
2149
+  font-weight: 500;
2150
+  cursor: pointer;
2151
+  line-height: normal;
2152
+  justify-content: center;
2153
+  align-items: end;
2154
+}
2155
+
2156
+#sendMsgConvBtn:hover {
2157
+  background-color:  #3bb397 !important;
2158
+  box-shadow: 0 0 6px rgba(0, 0, 0, 0.23);
2159
+  -webkit-box-shadow: 0 0 6px rgba(0, 0, 0, 0.23);
2160
+  -moz-box-shadow: 0 0 6px rgba(0, 0, 0, 0.23);
2161
+}
2162
+
2163
+#sendMsgConvBtn:active {
2164
+  background-color: #33a087 !important;
2165
+  box-shadow: 0 0 6px rgba(0, 0, 0, 0.23);
2166
+  -webkit-box-shadow: 0 0 6px rgba(0, 0, 0, 0.23);
2167
+  -moz-box-shadow: 0 0 6px rgba(0, 0, 0, 0.23);
2168
+}
2169
+
2170
+#saveDispName, #alertOk {
2171
+  display: block;
2172
+  border-radius: 20px !important;
2173
+  padding: 0px 14px !important;
2174
+  margin: 10px auto !important;
2175
+  min-height: 30px !important;
2176
+  height: 30px !important;
2177
+  color: #ffffff !important;
2178
+  background-color: #40c1a3 !important;
2179
+}
2180
+
2181
+#cancelOkWrap {
2182
+  display: block;
2183
+  width: 100%; 
2184
+  margin: 10px auto !important;
2185
+  text-align: center;
2186
+}
2187
+
2188
+#confirmOk, #confirmCancel {
2189
+  display: inline-block;
2190
+  min-width: 76px;
2191
+  border-radius: 20px !important;
2192
+  padding: 0px 14px !important;
2193
+  margin: 0 5px;
2194
+  min-height: 30px !important;
2195
+  height: 30px !important;
2196
+  color: #ffffff !important;
2197
+  background-color: #40c1a3 !important;
2198
+}
2199
+
2200
+#saveDispName:hover, #alertOk:hover, #confirmOk:hover, #confirmCancel:hover {
2201
+  background-color:  #3bb397 !important;
2202
+}
2203
+
2204
+#saveDispName:active, #alertOk:active, #confirmOk:active, #confirmCancel:active {
2205
+  background-color: #33a087 !important;
2206
+}
2207
+
2208
+#sendMsgReply {
2209
+  display: none;
2210
+}
2211
+
2212
+#sendMsgConv {
2213
+  display: block;
2214
+  width: 558px;
2215
+  height: auto;
2216
+  margin: 0 auto;
2217
+  border: none;
2218
+}
2219
+
2220
+#sendMsgConv td {
2221
+  background-color: #ffffff;
2222
+  border: none;
2223
+}
2224
+
2225
+#sendMsgConvText {
2226
+  display: inline-block;
2227
+  width: 558px;
2228
+  height: 72px;
2229
+  padding: 3px 5px;
2230
+  color: #000000;
2231
+  text-align: left;
2232
+  font-family: 'Inter';
2233
+  font-size: 15px;
2234
+  border-radius: 6px;
2235
+  resize: none;
2236
+  white-space: pre-wrap;
2237
+  border: 1px solid #dedede;
2238
+  background-color: #ffffff;
2239
+  overflow-y: auto;
2240
+}
2241
+
2242
+#fromPhoneNmbrConv {
2243
+  display: inline-block;
2244
+  width: 50%;
2245
+  height: auto;
2246
+  margin: 6px 0px 2px 10px;
2247
+  font-size: 14.5px;
2248
+  font-weight: 500;
2249
+  color: #222222;
2250
+}
2251
+
2252
+#toPhoneNmbrConv {
2253
+  display: inline-block;
2254
+  width: 50%;
2255
+  height: auto;
2256
+  margin: 6px 0px 2px -20px;
2257
+  font-size: 14.5px;
2258
+  font-weight: 500;
2259
+  color: #222222;
2260
+  text-align: right;
2261
+}
2262
+
2263
+#selectFromNbConv {
2264
+  height: 26px;
2265
+  width: auto;
2266
+  margin: 0;
2267
+  text-align: left;
2268
+  color: #222222;
2269
+  background-color: #ffffff !important;
2270
+  border: 1px solid #d8d8d8;
2271
+}
2272
+
2273
+#listAllMsgsFromTo {
2274
+  display: block;
2275
+  position: absolute;
2276
+  width: 600px;
2277
+  height: 490px;
2278
+  font-family: 'Inter' !important;
2279
+  white-space: pre-wrap;
2280
+  border-radius: 6px;
2281
+  background-color: #ffffff;
2282
+  box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
2283
+  -webkit-box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
2284
+  -moz-box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
2285
+  z-index: 5100;
2286
+}
2287
+
2288
+#listAllMsgsConv {
2289
+  display: block;
2290
+  position: absolute;
2291
+  width: 600px;
2292
+  height: 490px;
2293
+  font-family: 'Inter' !important;
2294
+  white-space: pre-wrap;
2295
+  border-radius: 6px;
2296
+  background-color: #ffffff;
2297
+  box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
2298
+  -webkit-box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
2299
+  -moz-box-shadow: 0 0 23px rgba(0, 0, 0, 0.23);
2300
+  z-index: 5100;
2301
+}
2302
+
2303
+#expandWindowRpl {
2304
+  display: block;
2305
+  margin: 4px auto 0 auto;
2306
+  cursor: pointer;
2307
+}
2308
+
2309
+#dragDispNmWindow {
2310
+  display: block;
2311
+  position: relative;
2312
+  width: 40px;
2313
+  height: 20px;
2314
+  margin:-3px auto 0px auto;
2315
+  cursor: grab;
2316
+  text-align: center;
2317
+}
2318
+
2319
+#draglstMsgmWindow {
2320
+  display: block;
2321
+  position: relative;
2322
+  width: 500px;
2323
+  height: 20px;
2324
+  margin:-3px auto 0px auto;
2325
+  cursor: grab;
2326
+  text-align: center;
2327
+}
2328
+
2329
+#draglstMsgmWindowsc {
2330
+  display: block;
2331
+  position: absolute;
2332
+  width: 100%;
2333
+  height: 14px;
2334
+  bottom: 3px;
2335
+  cursor: grab;
2336
+  text-align: center;
2337
+}
2338
+
2339
+#frmMsgLstWrap {
2340
+  display: block;
2341
+  position: relative;
2342
+  width: 560px;
2343
+  height: 400px;
2344
+  margin: 0 auto;
2345
+  overflow-y: auto;
2346
+  overflow-x: hidden;
2347
+}
2348
+
2349
+#frmMsgLstTbl {
2350
+  display: block;
2351
+  position: relative;
2352
+  width: 100%;
2353
+  height: 100%;
2354
+}
2355
+
2356
+#frmMsgLstTbl td {
2357
+  text-align: left;
2358
+  vertical-align: top;
2359
+  background-color: #ffffff !important;
2360
+}
2361
+
2362
+.groupedLstNamespn {
2363
+  display: block;
2364
+  position: fixed;
2365
+  width: 130px;
2366
+  height: auto;
2367
+  padding: 0px 0px 0px 4px;
2368
+  overflow-y: auto;
2369
+  white-space: pre-wrap;
2370
+}
2371
+
2372
+#msgListRowCell {
2373
+  display: block;
2374
+  width: 428px;
2375
+  height: auto;
2376
+  min-height: 358px;
2377
+  margin: 0px 0px 0px 130px;
2378
+  padding: 0px 0px 0px 4px;
2379
+  overflow: scroll;
2380
+  white-space: nowrap;
2381
+}
2382
+
2383
+.dispNameListAll {
2384
+  display: block;
2385
+  width: 100%;
2386
+  height: auto;
2387
+  border: 1px solid #c6cedb;
2388
+  border-radius: 20px;
2389
+  margin: 6px 0px 0px 0px;
2390
+  color: #04957b;
2391
+  font-size: 13px;
2392
+  padding: 0px 9px;
2393
+  text-align: center;
2394
+  font-weight: 500;
2395
+  cursor: pointer;
2396
+}
2397
+
2398
+#selectAllChckbx:hover {
2399
+  cursor: pointer;
2400
+}
2401
+
2402
+.indivchckbx:hover {
2403
+  cursor: pointer;
2404
+}
2405
+
2406
+.selectsmsdv {
2407
+  width: 30px;
2408
+  padding: 5px 5px 5px 7px;
2409
+  text-align: center;
2410
+}
2411
+
2412
+#selectalldv {
2413
+  width: 30px;
2414
+  padding: 5px 5px 5px 7px;
2415
+}
2416
+
2417
+.indivfilter {
2418
+  height: 30px;
2419
+  font-weight: bold;
2420
+  padding: 0px;
2421
+}
2422
+
2423
+.selectalldvfilter {
2424
+  border: 1px solid #f3f3f3;
2425
+  padding: 3px;
2426
+  margin: 0px; 
2427
+}
2428
+
2429
+.filterbuttonsrec, .filterbuttonsent {
2430
+  display: block;
2431
+  position: relative;
2432
+  margin: 5px auto !important;
2433
+  border-radius: 3px !important;
2434
+  background-color: #ffffff !important;
2435
+  background-image: url('../img/filter_icon.svg');
2436
+  background-repeat: no-repeat;
2437
+  background-position: center center;
2438
+  cursor: pointer;
2439
+}
2440
+
2441
+#clearrecfilters, #clearsentfilters, #cleargrpfilter {
2442
+  display: inline-block;
2443
+  width: 22px;
2444
+  height: 22px;
2445
+  background-color: #ffffff;
2446
+  background-image: url('../img/clearfilters.svg');
2447
+  background-repeat: no-repeat;
2448
+  background-position: center center;
2449
+  margin: 0px 0px 8px 0px;
2450
+  border: none;
2451
+  cursor: pointer;
2452
+}
2453
+
2454
+#deleterecrows, #deletesentrows {
2455
+  display: inline-block;
2456
+  width: 16px;
2457
+  height: 20px;
2458
+  background-color: #ffffff;
2459
+  background-image: url('../img/garbage.svg');
2460
+  background-repeat: no-repeat;
2461
+  background-position: center center;
2462
+  margin: 0px 0px 4px 0px;
2463
+  border: none;
2464
+  cursor: pointer;
2465
+}
2466
+
2467
+#deleterecrows:active, #deletesentrows:active {
2468
+  background-image: url('../img/garbage_bright.svg');
2469
+}
2470
+
2471
+#toptablerec, #toptablesent, #toptablegrp {
2472
+  display: block;
2473
+  position: sticky;
2474
+  top: 0px;
2475
+  height: 27px;
2476
+  width: 100%;
2477
+  z-index: 1001;
2478
+}
2479
+
2480
+.topbuttonandpage {
2481
+  display: block;
2482
+  position: relative;
2483
+  width: 100%;
2484
+  height: 27px;
2485
+  border-radius: 0px 24px 0px 0px;
2486
+  background: #FFFFFF;
2487
+  z-index: 1001;
2488
+}
2489
+
2490
+#paginationrec, #paginationsent, #paginationgrp {
2491
+   display: block;
2492
+   position: relative;
2493
+   float: right;
2494
+   width: auto;
2495
+   margin: -25px 14px 0px 0px;
2496
+   font-size: 15px;
2497
+   font-weight: 600;
2498
+   color: #0082C9;
2499
+   z-index: 1002;
2500
+}
2501
+
2502
+.arrowDownCl {
2503
+   background-image: url('../img/arrowDown.svg');
2504
+   background-repeat: no-repeat;
2505
+   background-position: center center;
2506
+   z-index: 1010;
2507
+}
2508
+
2509
+.arrowUpCl {
2510
+   background-image: url('../img/arrowUp.svg');
2511
+   background-repeat: no-repeat;
2512
+   background-position: center center;
2513
+   z-index: 1010;   
2514
+}
2515
+
2516
+@media (max-width: 1020px) {
2517
+  #recarrow, #sentarrow {
2518
+    display: block;
2519
+    position: relative;
2520
+    float: left;
2521
+    margin: 3.8px 0px 0px 50px;
2522
+    width: 17px;
2523
+    height: 17px;
2524
+    border: none;
2525
+    cursor: pointer;
2526
+  }
2527
+}
2528
+
2529
+@media (min-width: 1021px) {
2530
+  #recarrow, #sentarrow {
2531
+    display: block;
2532
+    position: relative;
2533
+    float: left;
2534
+    margin: 3.8px 0px 0px 7px;
2535
+    width: 17px;
2536
+    height: 17px;
2537
+    border: none;
2538
+    cursor: pointer;
2539
+  }
2540
+}
2541
+
2542
+#totalrecmessages, #totalsentmessages, #totalgrpmessages {
2543
+  display: block;
2544
+  position: relative;
2545
+  padding: 10px 0px 0px 7px;
2546
+  font-size: 14px;
2547
+  font-weight: bold;
2548
+  color: #4cbc86;
2549
+}
2550
+
2551
+.pagenumbers, .pagenumbersbottom, .pagenumbersrec, .pagenumbersbottomrec, .pagenumbersgrp {
2552
+  color: #0082C9;
2553
+}
2554
+
2555
+#dbidtextsent {
2556
+  display: block;
2557
+  margin: auto;
2558
+  width: 95%;
2559
+  padding: 0 3px !important;
2560
+  text-align: center;
2561
+}
2562
+
2563
+#dbidtextrec {
2564
+  display: block;
2565
+  margin: auto;
2566
+  width: 95%;
2567
+  padding: 0 3px !important;
2568
+  text-align: center;
2569
+}
2570
+
2571
+#useridtext {
2572
+  display: block;
2573
+  margin: auto;
2574
+  width: 95%;
2575
+}
2576
+
2577
+#useridtextrec {
2578
+  display: block;
2579
+  margin: auto;
2580
+  width: 95%;
2581
+}
2582
+
2583
+#messageidtext {
2584
+  display: block;
2585
+  margin: auto;
2586
+  width: 95%;
2587
+}
2588
+
2589
+#messageidtextrec {
2590
+  display: block;
2591
+  margin: auto;
2592
+  width: 95%;
2593
+}
2594
+
2595
+#datetext {
2596
+  display: block;
2597
+  margin: auto;
2598
+  width: 95px;
2599
+}
2600
+
2601
+#datetextrec {
2602
+  display: block;
2603
+  margin: auto;
2604
+  width: 95%;
2605
+}
2606
+
2607
+#fromtext {
2608
+  display: block;
2609
+  margin: auto;
2610
+  width: 95%;
2611
+}
2612
+
2613
+#fromtextrec {
2614
+  display: block;
2615
+  margin: auto;
2616
+  width: 95%;
2617
+}
2618
+
2619
+#totext {
2620
+  display: block;
2621
+  margin: auto;
2622
+  width: 95%;
2623
+}
2624
+
2625
+#totextrec {
2626
+  display: block;
2627
+  margin: auto;
2628
+  width: 95%;
2629
+}
2630
+
2631
+#networktext {
2632
+  display: block;
2633
+  margin: auto;
2634
+  width: 95%;
2635
+}
2636
+
2637
+#pricetext {
2638
+  display: block;
2639
+  margin: auto;
2640
+  width: 95%;
2641
+}
2642
+
2643
+#statustext {
2644
+  display: block;
2645
+  margin: auto;
2646
+  width: 95%;
2647
+}
2648
+
2649
+#deliveryrcpttext {
2650
+  display: block;
2651
+  margin: auto;
2652
+  width: 95%;
2653
+}
2654
+
2655
+#messagetext {
2656
+  display: block;
2657
+  margin: auto;
2658
+  width: 95%;
2659
+}
2660
+
2661
+#messagetextrec {
2662
+  display: block;
2663
+  margin: auto;
2664
+  width: 95%;
2665
+}
2666
+
2667
+#databaseidfilter {
2668
+  display: block;
2669
+  margin-left: auto;
2670
+  margin-right: auto;
2671
+}
2672
+
2673
+#sentstatuscolumn {
2674
+  max-width: 160px;
2675
+}
2676
+
2677
+.useridcolrec {
2678
+  width: 124px;
2679
+  background-color: #ffffff;
2680
+  text-align: center;
2681
+}
2682
+
2683
+.messageidcolsent {
2684
+  overflow: visible;
2685
+  word-break: break-all;
2686
+  text-align: center;
2687
+}
2688
+
2689
+.messageidcolrec {
2690
+  overflow: visible;
2691
+  word-break: break-all;
2692
+  width: 420px;
2693
+  text-align: center;
2694
+}
2695
+
2696
+.datecolrec {
2697
+  width: 160px;
2698
+  text-align: center;
2699
+}
2700
+
2701
+.fromcolumnrec {
2702
+  width: 140px;
2703
+  text-align: center;
2704
+  background-color: #f2fff5;
2705
+}
2706
+
2707
+.tocolrec {
2708
+  width: 140px;
2709
+  background-color: #f2fbff;
2710
+  text-align: center;
2711
+}
2712
+
2713
+.networkcolumnsent {
2714
+  max-width: 90px;
2715
+  background-color: #ffffff;
2716
+  word-break: break-word;
2717
+  text-align: center;
2718
+}
2719
+
2720
+.useridcolsent, .pricecolumnsent, .statuscolumnsent, .deliveryrcptcolsent {
2721
+  background-color: #ffffff;
2722
+  text-align: center;
2723
+}
2724
+
2725
+.tocolumnsent {
2726
+  background-color: #f2fbff;
2727
+  text-align: center;
2728
+}
2729
+
2730
+.fromcolumnsent {
2731
+  background-color: #f2fff5;
2732
+  text-align: center;
2733
+}
2734
+
2735
+.active {
2736
+  color: #c62b71;
2737
+}
2738
+
2739
+#deleteoldmssgs {
2740
+  display: inline-block;
2741
+  position: relative;
2742
+  margin: 10px 0px 10px 1px;
2743
+  font-size: 15px;
2744
+  font-weight: bold;
2745
+}
2746
+
2747
+#deleteoldsms {
2748
+  display: none;
2749
+  background: #e8f6ff;
2750
+  border-radius: 6px;
2751
+  padding: 5px;
2752
+}
2753
+
2754
+#delOldrecSMS, #delOldsentSMS {
2755
+  display: block;
2756
+  background-color: #0082C9;
2757
+  color: #ffffff;
2758
+  margin: 10px 0px 10px 5px;
2759
+  border-radius: 20px;
2760
+  font-family: 'Open Sans';
2761
+  font-size: 14px;
2762
+}
2763
+
2764
+#delOldrecSMS:active, #delOldsentSMS:active {
2765
+  background: #00a2f9;
2766
+}
2767
+
2768
+#delsetrows {
2769
+  display: block;
2770
+  padding: 5px;
2771
+}
2772
+
2773
+.deletesmsolder {
2774
+  display: inline;
2775
+  font-size: 15px;
2776
+  font-weight: bold;
2777
+}
2778
+
2779
+#oldrecSmsInterval, #oldsentSmsInterval {
2780
+  display: inline;
2781
+  width: 60px;
2782
+  height: 25px;
2783
+  padding: 0px 0px 0px 10px;
2784
+  font-family: 'Inter';
2785
+  font-size: 14px;
2786
+  font-weight: 600;
2787
+  border-radius: 20px;
2788
+}
2789
+
2790
+#upArrow {
2791
+  background-image: url("../img/arrow-top.svg");
2792
+  background-repeat: no-repeat;
2793
+  background-color: transparent !important;
2794
+  opacity: 0.30;
2795
+  position: fixed;
2796
+  bottom: 40px;
2797
+  right: 4px;
2798
+  width: 50px;
2799
+  height: 50px;
2800
+  border: none;
2801
+  cursor: pointer;
2802
+  display: none;
2803
+  z-index: 1010;
2804
+}
2805
+
2806
+#upArrow:hover {
2807
+  opacity: 1;
2808
+}
2809
+
2810
+#arrowupWrap {
2811
+  display: block;
2812
+  position: sticky;
2813
+  width: 21px;
2814
+  height: 21px;
2815
+  bottom: 12px;
2816
+  left: 530px;
2817
+}
2818
+
2819
+#upArrowSmall {
2820
+  position: relative;
2821
+  background-image: url("../img/arrow-top-small.svg");
2822
+  background-repeat: no-repeat;
2823
+  background-color: transparent !important;
2824
+  width: 21px;
2825
+  height: 21px;
2826
+  opacity: 0.30;
2827
+  border: none;
2828
+  cursor: pointer;
2829
+  display: none;
2830
+  z-index: 5300;
2831
+}
2832
+
2833
+#upArrowSmall:hover {
2834
+  opacity: 1;
2835
+}
2836
+
2837
+.opensmsfolder {
2838
+  display: block;
2839
+  position: relative;
2840
+  margin: 10px 0px 10px 0px !important;
2841
+  padding: 7px 0 7px 0 !important;
2842
+  width: 100% !important;
2843
+  color: #FFFFFF !important;
2844
+  font-family: 'Open Sans' !important;
2845
+  font-size: 15px !important;
2846
+  background-color: #CB99C5 !important;
2847
+}
2848
+
2849
+.opensmsfolder:hover {
2850
+  border: 2px;
2851
+  background-color: #c18bba !important;
2852
+}
2853
+
2854
+.opensmsfolder:active {
2855
+  background-color: #b777af !important;
2856
+  border: 2px;
2857
+  color: #FFFFFF !important;
2858
+  border-color: #b777af;
2859
+}
2860
+
2861
+.opensmsfolder:focus {
2862
+  background-color: #a3669b !important;
2863
+  border: 2px;
2864
+  border-color: #a3669b;
2865
+}
2866
+
2867
+#save_sms_settings {
2868
+  display: inline-block;
2869
+  border-radius: 8px !important;
2870
+  padding: 0px 14px !important;
2871
+  color: #ffffff !important;
2872
+  background-color: #1e89c2 !important;
2873
+}
2874
+
2875
+#save_sms_settings:hover {
2876
+  background-color: #0369a0 !important;
2877
+}
2878
+
2879
+#save_sms_settings:active {
2880
+  background-color: #025480 !important;
2881
+}
2882
+
2883
+#conversationsTable {
2884
+  display: block;
2885
+  position: relative;
2886
+  top: 0;
2887
+  bottom: 0;
2888
+  width: 100%;
2889
+  height: 100%;
2890
+  font-size: 14px;
2891
+  z-index: 50;
2892
+  background-color: #ffffff;
2893
+}
2894
+
2895
+#conversationsTable td {
2896
+  text-align: left;
2897
+  vertical-align: top;
2898
+  border: 1px solid #f3f3f3;
2899
+  padding: 2px;
2900
+}
2901
+
2902
+#conversationsTable tr:hover {
2903
+  background-color: #ffffff;
2904
+}
2905
+
2906
+/* Timer for page auto-refresh */
2907
+#refreshTimerSent {
2908
+  display: none;
2909
+  margin: 1.5px 0px 0px 6px;
2910
+}
2911
+
2912
+.arftimer {
2913
+  background: -webkit-linear-gradient(left, #3c76bd 50%, #eee 50%);
2914
+  border-radius: 100%;
2915
+  height: calc(var(--size) * 1px);
2916
+  width: calc(var(--size) * 1px);
2917
+  position: relative;
2918
+  -webkit-animation: time calc(var(--duration) * 1s) steps(1000, start) infinite;
2919
+  -webkit-mask: radial-gradient(transparent 50%,#000 50%);
2920
+  mask: radial-gradient(transparent 50%,#000 50%);
2921
+}
2922
+.arfmask {
2923
+  border-radius: 100% 0 0 100% / 50% 0 0 50%;
2924
+  height: 100%;
2925
+  left: 0;
2926
+  position: absolute;
2927
+  top: 0;
2928
+  width: 50%;
2929
+  -webkit-animation: mask calc(var(--duration) * 1s) steps(500, start) infinite;
2930
+  -webkit-transform-origin: 100% 50%;
2931
+}
2932
+@-webkit-keyframes time {
2933
+  100% {
2934
+      -webkit-transform: rotate(360deg);
2935
+  }
2936
+}
2937
+@-webkit-keyframes mask {
2938
+  0% {
2939
+      background: #eee;
2940
+      -webkit-transform: rotate(0deg);
2941
+  }
2942
+  50% {
2943
+      background: #eee;
2944
+      -webkit-transform: rotate(-180deg);
2945
+  }
2946
+  50.01% {
2947
+      background: #3c76bd;
2948
+      -webkit-transform: rotate(0deg);
2949
+  }
2950
+  100% {
2951
+      background: #3c76bd;
2952
+      -webkit-transform: rotate(-180deg);
2953
+  }
2954
+}
2955
+
2956
+#sms_relentless_adm {
2957
+  font-family: 'Inter';
2958
+}
2959
+
2960
+.arplAuthor, .arplPhoneNmbr, .selectArplMode, .daysInWeek, .startDate, .endDate, .arplText, .restrAuthor {
2961
+  font-family: 'Inter' !important;
2962
+}
2963
+
2964
+.indivfilterrec, .indivfiltersent {
2965
+  font-family: 'Inter';
2966
+  padding: 0 4px !important;
2967
+}
2968
+
2969
+/* Changes for dark themes */
2970
+[data-theme-dark] .srheader,
2971
+[data-theme-dark-highcontrast] .srheader {
2972
+  display: block;
2973
+  position: relative;
2974
+  margin: 0px 0px 7px 0px;
2975
+  color: #fafafa;
2976
+  font-size: 15px;
2977
+  font-weight: 700;
2978
+}
2979
+
2980
+[data-theme-dark] #sendtomultiple,
2981
+[data-theme-dark-highcontrast] #sendtomultiple {
2982
+  display: inline-block;
2983
+  position: relative;
2984
+  margin: 10px 0px 12px 0px;
2985
+  color: #fafafa;
2986
+  font-size: 15px;
2987
+  font-weight: 700;
2988
+}
2989
+
2990
+[data-theme-dark] #entermessage,
2991
+[data-theme-dark-highcontrast] #entermessage {
2992
+  display: block;
2993
+  position: relative;
2994
+  margin: 10px 0px 0px 0px;
2995
+  color: #fafafa;
2996
+  font-size: 15px;
2997
+  font-weight: 700;
2998
+}
2999
+
3000
+[data-theme-dark] #sendmediafl,
3001
+[data-theme-dark-highcontrast] #sendmediafl {
3002
+  display: block;
3003
+  position: relative;
3004
+  margin: 0px 0px 20px 0px;
3005
+  color: #fafafa;
3006
+  font-size: 15px;
3007
+  font-weight: 700;
3008
+}
3009
+
3010
+[data-theme-dark] #deleteoldmssgs,
3011
+[data-theme-dark-highcontrast] #deleteoldmssgs {
3012
+  display: inline-block;
3013
+  position: relative;
3014
+  margin: 10px 0px 10px 1px;
3015
+  color: #fafafa;
3016
+  font-size: 15px;
3017
+  font-weight: 700;
3018
+}
3019
+
3020
+[data-theme-dark] #smsto,
3021
+[data-theme-dark-highcontrast] #smsto {
3022
+  display: block;
3023
+  width: 99%;
3024
+  max-height: 32px;
3025
+  padding: 0px 15px 0px 15px;
3026
+  color: #fafafa;
3027
+  font-family: 'Inter';
3028
+  font-size: 15px;
3029
+  font-weight: 600;
3030
+  border-radius: 20px;
3031
+}
3032
+
3033
+[data-theme-dark] #smstext,
3034
+[data-theme-dark-highcontrast] #smstext {
3035
+  display: inline-block;
3036
+  color: #ffffff;
3037
+  width: 100%;
3038
+  height: 130px;
3039
+  text-align: left;
3040
+  font-family: 'Inter';
3041
+  font-size: 15px;
3042
+  border-radius: 6px;
3043
+  resize: vertical;
3044
+  white-space: pre-wrap;
3045
+}
3046
+
3047
+
3048
+[data-theme-dark] .arplText,
3049
+[data-theme-dark-highcontrast] .arplText {
3050
+  display: inline-block;
3051
+  color: #fafafa;
3052
+  width: 330px;
3053
+  height: 184px;
3054
+  font-size: 15px;
3055
+  text-align: left;
3056
+  border: 1px solid #000;
3057
+  border-radius: 6px;
3058
+  margin: 0px 1px 0px 0px;
3059
+  resize: vertical;
3060
+  white-space: pre-wrap;
3061
+  overflow: auto;
3062
+}
3063
+
3064
+[data-theme-dark] #oldrecSmsInterval, [data-theme-dark] #oldsentSmsInterval,
3065
+[data-theme-dark-highcontrast] #oldrecSmsInterval, [data-theme-dark-highcontrast] #oldsentSmsInterval {
3066
+  display: inline;
3067
+  width: 60px;
3068
+  height: 25px;
3069
+  padding: 0px 0px 0px 10px;
3070
+  color: #fafafa;
3071
+  font-family: 'Inter';
3072
+  font-size: 14px;
3073
+  font-weight: 600;
3074
+  border-radius: 20px;
3075
+}
3076
+
3077
+[data-theme-dark] .tooltipbalanceid #infobalance,
3078
+[data-theme-dark-highcontrast] .tooltipbalanceid #infobalance {
3079
+  display: block;
3080
+  position: relative;
3081
+  margin: 4px 14px 0px 0px;
3082
+  color: #fafafa;
3083
+  font-size: 21px;
3084
+  font-weight: bold;
3085
+  font-family: 'Open Sans';
3086
+  font-style: italic;
3087
+  z-index: 6;
3088
+}
3089
+
3090
+[data-theme-dark] #infotipid,
3091
+[data-theme-dark-highcontrast] #infotipid {
3092
+  display: block;
3093
+  position: relative;
3094
+  margin: 4px 14px 0px 0px;
3095
+  color: #fafafa;
3096
+  font-size: 19px;
3097
+  font-weight: 700;
3098
+  font-family: 'Open Sans';
3099
+  font-style: italic;
3100
+  z-index: 5;
3101
+}
3102
+
3103
+[data-theme-dark] #inforestrict,
3104
+[data-theme-dark-highcontrast] #inforestrict {
3105
+  display: inline-block;
3106
+  position: relative;
3107
+  margin: -2px 0px 0px 10px;
3108
+  color: #fafafa;
3109
+  font-size: 18px;
3110
+  font-weight: bold;
3111
+  font-family: 'Open Sans';
3112
+  font-style: italic;
3113
+  cursor: pointer;
3114
+}
3115
+
3116
+[data-theme-dark] .fortooltip .texttooltip, [data-theme-dark] .maxmessagelength .texttooltip,
3117
+[data-theme-dark-highcontrast] .fortooltip .texttooltip, [data-theme-dark-highcontrast] .maxmessagelength .texttooltip {
3118
+  font-family: 'Open Sans';
3119
+  font-style: italic;
3120
+  color: #fafafa;
3121
+  font-size: 19px;
3122
+  font-weight: 700;
3123
+  margin: 0px 0px 4px 4px;
3124
+}
3125
+
3126
+[data-theme-dark] #uploadfileforsms,
3127
+[data-theme-dark-highcontrast] #uploadfileforsms {
3128
+  margin-left: 7px;
3129
+  background-color: #434343;
3130
+  border-radius: 3px !important;
3131
+}
3132
+
3133
+[data-theme-dark] #uploadfileformms,
3134
+[data-theme-dark-highcontrast] #uploadfileformms {
3135
+  margin-left: 21px;
3136
+  background-color: #434343;
3137
+  border-radius: 3px !important;
3138
+}
3139
+
3140
+[data-theme-dark] .smsnbformat a,
3141
+[data-theme-dark-highcontrast] .smsnbformat a {
3142
+  color: #cedfff !important;
3143
+}
3144
+
3145
+[data-theme-dark] .smsnbformat font,
3146
+[data-theme-dark-highcontrast] .smsnbformat font {
3147
+  color: #f7547a !important;
3148
+}
3149
+
3150
+[data-theme-dark] .indivfiltersent, [data-theme-dark] .indivfilterrec,
3151
+[data-theme-dark-highcontrast] .indivfiltersent, [data-theme-dark-highcontrast] .indivfilterrec {
3152
+  color: #ffffff !important;
3153
+  padding: 0 4px !important;
3154
+  font-family: 'Inter';
3155
+}
3156
+
3157
+[data-theme-dark] #recSmsTable, [data-theme-dark] #groupedSmsTable, [data-theme-dark] #sentSmsTable,
3158
+[data-theme-dark-highcontrast] #recSmsTable, [data-theme-dark-highcontrast] #groupedSmsTable, [data-theme-dark-highcontrast] #sentSmsTable {
3159
+  color: #000000 !important;
3160
+}
3161
+
3162
+[data-theme-dark] .providerSettings .setlabeltext,
3163
+[data-theme-dark-highcontrast] .providerSettings .setlabeltext {
3164
+  color: #272727;
3165
+}
3166
+
3167
+[data-theme-dark] .providerName,
3168
+[data-theme-dark-highcontrast] .providerName  {
3169
+  font-size: 18px;
3170
+  font-weight: bold;
3171
+  margin-bottom: 20px;
3172
+  color: #272727;
3173
+}
3174
+
3175
+[data-theme-dark] .selectHrMin, 
3176
+[data-theme-dark-highcontrast] .selectHrMin,
3177
+[data-theme-dark] .startDate,
3178
+[data-theme-dark-highcontrast] .startDate,
3179
+[data-theme-dark] .endDate,
3180
+[data-theme-dark-highcontrast] .endDate {
3181
+  color: #ffffff !important;
3182
+}
3183
+
3184
+[data-theme-dark] #infoautoreply, [data-theme-dark] #infoautoreplyst, [data-theme-dark] #infoautoreplypn,
3185
+[data-theme-dark-highcontrast] #infoautoreply, [data-theme-dark-highcontrast] #infoautoreplyst, [data-theme-dark-highcontrast] #infoautoreplypn {
3186
+  color: #ffffff;
3187
+}
3188
+
3189
+[data-theme-dark] .generateUrl,
3190
+[data-theme-dark-highcontrast] .generateUrl {
3191
+  color: #013351 !important;
3192
+  font-family: 'Inter';
3193
+}
0 3194
new file mode 100644
... ...
@@ -0,0 +1,867 @@
1
+/**
2
+ * @copyright 2021 Double Bastion LLC <www.doublebastion.com>
3
+ *
4
+ * @author Double Bastion LLC
5
+ *
6
+ * @license GNU AGPL version 3 or any later version
7
+ *
8
+ * This program is free software; you can redistribute it and/or
9
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
10
+ * License as published by the Free Software Foundation; either
11
+ * version 3 of the License, or any later version.
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
17
+ *
18
+ * You should have received a copy of the GNU Affero General Public
19
+ * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
+ *
21
+ */
22
+
23
+$(document).ready(function() {
24
+
25
+  var userid = "<?php p($userId); ?>";
26
+  var ctappdir = 'apps';
27
+
28
+  // Get app directory
29
+  var getappdirurl = OC.generateUrl('/apps/sms_relentless/user/getappdirectory');
30
+
31
+  $.ajax({
32
+     method: 'GET',
33
+     url: getappdirurl + '/' + userid,
34
+     contentType: 'application/json',
35
+     success: function(appdirfdb) {
36
+
37
+                   ctappdir = appdirfdb;
38
+
39
+		  // Get admin settings
40
+		  var baseUrlget = OC.generateUrl('/apps/sms_relentless/user/getadminsettings');
41
+
42
+		  $.ajax({
43
+		     method: 'GET',
44
+		     url: baseUrlget + '/' + userid,
45
+		     contentType: 'application/json',
46
+		     success: function(settingsadm) {
47
+
48
+			  $("#telapi_key").val(settingsadm.telapi_key);
49
+			  $("#tel_pub_key").val(settingsadm.tel_pub_key);
50
+			  $("#telapi_url_rec").val(settingsadm.telapi_url_rec);
51
+			  $("#telapi_url").val(settingsadm.telapi_url);
52
+			  $("#messaging_profile_id").val(settingsadm.messaging_profile_id);
53
+			  $("#nexapi_key").val(settingsadm.nexapi_key);
54
+			  $("#nexapi_secret").val(settingsadm.nexapi_secret);
55
+			  $("#nexapi_url_rec").val(settingsadm.nexapi_url_rec);
56
+			  $("#nexapi_url").val(settingsadm.nexapi_url);
57
+			  $("#twilapi_key").val(settingsadm.twilapi_key);
58
+			  $("#twilapi_secret").val(settingsadm.twilapi_secret);
59
+			  $("#twilapi_url_rec").val(settingsadm.twilapi_url_rec);
60
+			  $("#twilapi_url").val(settingsadm.twilapi_url);
61
+			  $("#flowapi_key").val(settingsadm.flowapi_key);
62
+			  $("#flowapi_secret").val(settingsadm.flowapi_secret);
63
+			  $("#flowapi_url_rec").val(settingsadm.flowapi_url_rec);
64
+			  $("#flowapi_url").val(settingsadm.flowapi_url);
65
+			  $("#tel_sender_name").val(settingsadm.tel_sender_name);
66
+			  $("#nex_sender_name").val(settingsadm.nex_sender_name);
67
+			  $("#twil_sender_name").val(settingsadm.twil_sender_name);
68
+
69
+			  if (settingsadm.show_all_messages == 1) {
70
+			      $("#showallmessages").attr("checked", true);
71
+			  } else {
72
+			      $("#showallmessages").attr("checked", false);
73
+			  }
74
+
75
+			  var crntadmDispName = settingsadm.admdisplayname;
76
+			  var allRestrictions = settingsadm.restrictions;
77
+			  var allGroups = settingsadm.allgroups;
78
+			  var allUsers = settingsadm.allusers;
79
+			  var allGroupswadm = settingsadm.allgroupswadm;
80
+			  var allUserswadm = settingsadm.alluserswadm;
81
+			  var tnxallowedgrp = settingsadm.allowedkeysuse.tnx_groups_allowed;
82
+			  var tnxallowedusr = settingsadm.allowedkeysuse.tnx_users_allowed;
83
+			  var plvallowedgrp = settingsadm.allowedkeysuse.plv_groups_allowed;
84
+			  var plvallowedusr = settingsadm.allowedkeysuse.plv_users_allowed;
85
+			  var twlallowedgrp = settingsadm.allowedkeysuse.twl_groups_allowed;
86
+			  var twlallowedusr = settingsadm.allowedkeysuse.twl_users_allowed;
87
+			  var flrallowedgrp = settingsadm.allowedkeysuse.flr_groups_allowed;
88
+			  var flrallowedusr = settingsadm.allowedkeysuse.flr_users_allowed;
89
+
90
+			  // List all the groups and users allowed to access the API keys, for each provider
91
+			  if (tnxallowedgrp) {
92
+			      var tnxallowedgrparr = tnxallowedgrp.split("|");
93
+			      for (var g = 0; g < tnxallowedgrparr.length; g++) {
94
+				   $("#alwdakeyGrps-tnx").append("<div class='selectedGrps'>"+ tnxallowedgrparr[g] +"<img id='rmvGrp-tnx-"+ tnxallowedgrparr[g] +"' class='removeGroup' src='/" + ctappdir + "/sms_relentless/img/closewnd.svg' title='Remove this group'></div>");
95
+			      }
96
+			  }
97
+
98
+			  if (tnxallowedusr) {
99
+			      var tnxallowedusrarr = tnxallowedusr.split("|");
100
+			      for (var g = 0; g < tnxallowedusrarr.length; g++) {
101
+				   $("#alwdakeyUsrs-tnx").append("<div class='selectedUsrs'>"+ tnxallowedusrarr[g] +"<img id='rmvUsr-tnx-"+ tnxallowedusrarr[g] +"' class='removeUser' src='/" + ctappdir + "/sms_relentless/img/closewnd.svg' title='Remove this user'></div>");
102
+			      }
103
+			  }
104
+
105
+			  if (plvallowedgrp) {
106
+			      var plvallowedgrparr = plvallowedgrp.split("|");
107
+			      for (var g = 0; g < plvallowedgrparr.length; g++) {
108
+				   $("#alwdakeyGrps-plv").append("<div class='selectedGrps'>"+ plvallowedgrparr[g] +"<img id='rmvGrp-plv-"+ plvallowedgrparr[g] +"' class='removeGroup' src='/" + ctappdir + "/sms_relentless/img/closewnd.svg' title='Remove this group'></div>");
109
+			      }
110
+			  }
111
+
112
+			  if (plvallowedusr) {
113
+			      var plvallowedusrarr = plvallowedusr.split("|");
114
+			      for (var g = 0; g < plvallowedusrarr.length; g++) {
115
+				   $("#alwdakeyUsrs-plv").append("<div class='selectedUsrs'>"+ plvallowedusrarr[g] +"<img id='rmvUsr-plv-"+ plvallowedusrarr[g] +"' class='removeUser' src='/" + ctappdir + "/sms_relentless/img/closewnd.svg' title='Remove this user'></div>");
116
+			      }
117
+			  }
118
+
119
+			  if (twlallowedgrp) {
120
+			      var twlallowedgrparr = twlallowedgrp.split("|");
121
+			      for (var g = 0; g < twlallowedgrparr.length; g++) {
122
+				   $("#alwdakeyGrps-twl").append("<div class='selectedGrps'>"+ twlallowedgrparr[g] +"<img id='rmvGrp-twl-"+ twlallowedgrparr[g] +"' class='removeGroup' src='/" + ctappdir + "/sms_relentless/img/closewnd.svg' title='Remove this group'></div>");
123
+			      }
124
+			  }
125
+
126
+			  if (twlallowedusr) {
127
+			      var twlallowedusrarr = twlallowedusr.split("|");
128
+			      for (var g = 0; g < twlallowedusrarr.length; g++) {
129
+				   $("#alwdakeyUsrs-twl").append("<div class='selectedUsrs'>"+ twlallowedusrarr[g] +"<img id='rmvUsr-twl-"+ twlallowedusrarr[g] +"' class='removeUser' src='/" + ctappdir + "/sms_relentless/img/closewnd.svg' title='Remove this user'></div>");
130
+			      }
131
+			  }
132
+
133
+			  if (flrallowedgrp) {
134
+			      var flrallowedgrparr = flrallowedgrp.split("|");
135
+			      for (var g = 0; g < flrallowedgrparr.length; g++) {
136
+				   $("#alwdakeyGrps-flr").append("<div class='selectedGrps'>"+ flrallowedgrparr[g] +"<img id='rmvGrp-flr-"+ flrallowedgrparr[g] +"' class='removeGroup' src='/" + ctappdir + "/sms_relentless/img/closewnd.svg' title='Remove this group'></div>");
137
+			      }
138
+			  }
139
+
140
+			  if (flrallowedusr) {
141
+			      var flrallowedusrarr = flrallowedusr.split("|");
142
+			      for (var g = 0; g < flrallowedusrarr.length; g++) {
143
+				   $("#alwdakeyUsrs-flr").append("<div class='selectedUsrs'>"+ flrallowedusrarr[g] +"<img id='rmvUsr-flr-"+ flrallowedusrarr[g] +"' class='removeUser' src='/" + ctappdir + "/sms_relentless/img/closewnd.svg' title='Remove this user'></div>");
144
+			      }
145
+			  }
146
+
147
+
148
+			  // Create a list with all the available groups, excluding the admin group
149
+			  var grpsListItemswadm = "";
150
+			  $.each(allGroupswadm, function(key, value) {
151
+				 grpsListItemswadm += "<div class='groupsList'>"+ value +"</div>";
152
+			  });
153
+
154
+			  // Create a list with all the available users, excluding the admins
155
+			  var usersListItemswadm = "";
156
+			  $.each(allUserswadm, function(key, usrval) {
157
+				 usersListItemswadm += "<div class='usersList'>"+ usrval +"</div>";
158
+			  });
159
+			  
160
+
161
+			  function showListsalwdk() {
162
+
163
+			      // Append the list of available groups to the table of groups and users allowed to use the API keys
164
+			      $('[id^="showakeyGrps-"]').click(function() {
165
+				 var crtid = $(this).attr("id").split("-")[1];
166
+				 $("#grpsadapik-"+ crtid).remove();
167
+				 $("#showakeyGrps-"+ crtid).append("<div id='grpsadapik-"+ crtid +"' class='grpsList'>"+ grpsListItemswadm +"</div>");
168
+				 $("#adminOverlay").remove();
169
+				 $("#app-content").append("<div id='adminOverlay'></div>");
170
+				 $("#adminOverlay").css({ "width" : parseInt($("#sms_relentless_adm").width() + 400) +"px", "height" : $("#sms_relentless_adm").height() +"px" });
171
+
172
+				 $("#adminOverlay").click(function() { 
173
+				    $("#adminOverlay").remove();
174
+				    $("#grpsadapik-"+ crtid).remove();
175
+				    $("#usrsadapik-"+ crtid).remove();
176
+				 });
177
+
178
+				 // Select a group
179
+				 $(".groupsList").click(function() {
180
+				    var slctdGrp = $(this).text();
181
+				    $("#grpsadapik-"+ crtid).remove();
182
+				    var addedTxtgrp = $("#alwdakeyGrps-"+ crtid).text();
183
+
184
+				    if (addedTxtgrp.indexOf(slctdGrp) == -1) {
185
+					$("#alwdakeyGrps-"+ crtid).append("<div class='selectedGrps'>"+ slctdGrp +"<img id='rmvGrp-"+ crtid +"-"+ slctdGrp +"' class='removeGroup' src='/" + ctappdir + "/sms_relentless/img/closewnd.svg' title='Remove this group'></div>");
186
+				    } else { showAlert("That group has already been added!"); }
187
+
188
+				    // Remove a group from list
189
+				    $('[id^="rmvGrp-"]').click(function() {
190
+				       $(this).closest(".selectedGrps").remove();
191
+				    });
192
+				 });
193
+
194
+			      });
195
+
196
+			      // Append the list of available users to the table of groups and users allowed to use the API keys
197
+			      $('[id^="showakeyUsrs-"]').click(function() {
198
+
199
+				 var crtidusr = $(this).attr("id").split("-")[1];
200
+				 $("#usrsadapik-"+ crtidusr).remove();
201
+				 $("#showakeyUsrs-"+ crtidusr).append("<div id='usrsadapik-"+ crtidusr +"' class='usrsList'>"+ usersListItemswadm +"</div>");
202
+				 $("#adminOverlay").remove();
203
+				 $("#app-content").append("<div id='adminOverlay'></div>");
204
+				 $("#adminOverlay").css({ "width" : parseInt($("#sms_relentless_adm").width() + 400) +"px", "height" : $("#sms_relentless_adm").height() +"px" });
205
+
206
+				 $("#adminOverlay").click(function() { 
207
+				    $("#adminOverlay").remove(); 
208
+				    $("#grpsadapik-"+ crtidusr).remove();
209
+				    $("#usrsadapik-"+ crtidusr).remove();
210
+				 });
211
+
212
+				 // Select a user
213
+				 $(".usersList").click(function() {
214
+				    var slctdUsr = $(this).text();
215
+				    var addedTxtusr = $("#alwdakeyUsrs-"+ crtidusr).text();
216
+
217
+				    if (addedTxtusr.indexOf(slctdUsr) == -1) {
218
+					$("#alwdakeyUsrs-"+ crtidusr).append("<div class='selectedUsrs'>"+ slctdUsr +"<img id='rmvUsr-"+ crtidusr +"-"+ slctdUsr +"' class='removeUser' src='/" + ctappdir + "/sms_relentless/img/closewnd.svg' title='Remove this user'></div>");
219
+				    } else { showAlert("That user has already been added!"); }
220
+
221
+				    // Remove a user from list
222
+				    $('[id^="rmvUsr-"]').click(function() {
223
+				       $(this).closest(".selectedUsrs").remove();
224
+				    });
225
+				 });
226
+
227
+			      });
228
+
229
+			      // Remove a group from the list 
230
+			      $('[id^="rmvGrp-"]').click(function() {
231
+				 $(this).closest(".selectedGrps").remove();
232
+			      });
233
+
234
+			      // Remove a user from the list
235
+			      $('[id^="rmvUsr-"]').click(function() {
236
+				 $(this).closest(".selectedUsrs").remove();
237
+			      });
238
+
239
+			  }
240
+			  showListsalwdk();
241
+
242
+
243
+			  // Save the data
244
+			  function saveAlwdRow() {
245
+			     $('[id^="alwdrstsave-"]').unbind("click");
246
+			     $('[id^="alwdrstsave-"]').click(function(event) {
247
+
248
+				 event.preventDefault();
249
+				 var crntprov = $(this).attr("id").replace("alwdrstsave-", "");
250
+				 
251
+				 if ($(this).attr("value") == "Save") {
252
+
253
+				     var selGroups = [];
254
+				     $("#alwdakeyGrps-"+ crntprov +" .selectedGrps").each(function() {
255
+					selGroups.push($(this).text());
256
+				     });
257
+				     if (selGroups.length == 0) { selGroups.push(""); }
258
+
259
+				     var selUsers = [];
260
+				     $("#alwdakeyUsrs-"+ crntprov +" .selectedUsrs").each(function() {
261
+					selUsers.push($(this).text());
262
+				     });
263
+				     if (selUsers.length == 0) { selUsers.push(""); }
264
+
265
+				     // Check if the access key fields have been left empty
266
+				     if (crntprov == 'tnx' && ($("#telapi_key").val().trim() == '' || $("#tel_pub_key").val().trim() == '' || $("#messaging_profile_id").val().trim() == '')) {
267
+					 showAlert("Please first fill in the fields: 'Telnyx API Secret Key', 'Telnyx Account Public Key' and 'Messaging Profile ID'");
268
+					 return;
269
+				     } else if (crntprov == 'plv' && ($("#nexapi_key").val().trim() == '' || $("#nexapi_secret").val().trim() == '')) {
270
+					 showAlert("Please first fill in the fields: 'Plivo Auth ID' and 'Plivo Auth Token'.");
271
+					 return;
272
+				     } else if (crntprov == 'twl' && ($("#twilapi_key").val().trim() == '' || $("#twilapi_secret").val().trim() == '')) {
273
+					 showAlert("Please first fill in the fields: 'Twilio Account SID' and 'Twilio Auth Token'.");
274
+					 return;
275
+				     } else if (crntprov == 'flr' && ($("#flowapi_key").val().trim() == '' || $("#flowapi_secret").val().trim() == '')) {
276
+					 showAlert("Please first fill in the fields: 'Flowroute Access Key' and 'Flowroute Secret Key'.");
277
+					 return;
278
+				     }
279
+
280
+				     var saveAlwdUrl = OC.generateUrl('/apps/sms_relentless/user/updatekeysallowedusers');
281
+
282
+				     var alwddatatosend = { 
283
+					      userId: userid,
284
+					      groups: selGroups,
285
+					      users: selUsers,
286
+					      provider: crntprov
287
+				     };
288
+
289
+				     $.ajax({
290
+					   method: 'PUT',
291
+					   url: saveAlwdUrl + '/' + userid,
292
+					   contentType: 'application/json',
293
+					   data: JSON.stringify(alwddatatosend),
294
+					   success: function(messagesent) {
295
+					                if (messagesent == 'success') {
296
+					                    showAlert('The allowed groups and users have been successfully saved to the database! However, to be able to send and receive messages using the shared keys from above, the allowed users have to generate and save the 2 webhook URLs corresponding to this SMS provider, on their own Settings page.');
297
+					                } else if (messagesent != 'success' && messagesent != 'failure') {
298
+					                    showAlert(messagesent);
299
+					                } else if (messagesent == 'failure') {
300
+					                    showAlert('Error while trying to save the allowed groups and users!');
301
+					                }
302
+					   },
303
+					   error: function() {
304
+							showAlert('Error while attempting to save the allowed groups and users! You can check the Nextcloud log to find more details about this issue.');
305
+					   }
306
+				     });
307
+
308
+				     $(this).attr("value", "Edit");
309
+
310
+				} else {
311
+
312
+				     $("#alwdrstsave-"+ crntprov).attr("value", "Save");
313
+				}
314
+
315
+			     });
316
+			  }
317
+			  saveAlwdRow();
318
+
319
+
320
+
321
+			  // Phone number restrictions
322
+
323
+			  // Create a list with all the available groups
324
+			  var grpsListItems = "";
325
+			  $.each(allGroups, function(key, value) {
326
+				 grpsListItems += "<div class='groupsList'>"+ value +"</div>";
327
+			  });
328
+
329
+			  // Create a list with all the available users
330
+			  var usersListItems = "";
331
+			  $.each(allUsers, function(key, usrval) {
332
+				 usersListItems += "<div class='usersList'>"+ usrval +"</div>";
333
+			  });
334
+
335
+
336
+			  if (allRestrictions.length > 0) {
337
+			      var restrNmb = allRestrictions.length;
338
+			  } else {
339
+			      var restrNmb = 0;
340
+			  }
341
+
342
+
343
+			  // List the access restrictions for groups and users
344
+			  if (restrNmb == 0) {
345
+
346
+			      $("#phoneNmbrRestr").append("<tr><td><input type='text' class='restrAuthor' value='"+ crntadmDispName +"' disabled></td><td><select id='rstphn-"+ restrNmb +"' class='restrPhoneNmbr'></select></td><td><div id='rstgrp-"+ restrNmb +"' class='restrGroups'></div></td><td><div id='showGrps-"+ restrNmb +"' class='showAllGroups'><img src='/" + ctappdir + "/sms_relentless/img/group.svg' style='cursor:pointer' title='Show all groups'></div></td><td><div id='rstusr-"+ restrNmb +"' class='restrUsers'></div></td><td><div id='showUsr-"+ restrNmb +"' class='showAllUsers'><img src='/" + ctappdir + "/sms_relentless/img/user.svg' style='cursor:pointer' title='Show all users'></div></td><td><img id='rmRow-"+ restrNmb +"' class='removeRow' src='/" + ctappdir + "/sms_relentless/img/closewnd.svg' title='Remove this row from the database' style='cursor:pointer;margin:6px 7px 0px 6px;'></td><td><input type='submit' id='rstsave-"+ restrNmb +"' class='saveRestrictions' value='Save' title='Save Row' /></td></tr>");
347
+			      $("#phoneNmbrRestr").append("<div><img id='addRestrRow' src='/" + ctappdir + "/sms_relentless/img/add.svg' title='Add Row'></div>");
348
+
349
+			  } else {
350
+
351
+			      for (k = 0; k < restrNmb; k++) {
352
+
353
+				   if (allRestrictions[k].groups) {
354
+				       var groupsfdbpre = allRestrictions[k].groups.split("|");
355
+				       var groupsfdb = "";
356
+				       for (var g = 0; g < groupsfdbpre.length; g++) {
357
+					    groupsfdb += "<div class='selectedGrps'>"+ groupsfdbpre[g] +"<img id='rmvGrp-"+ groupsfdbpre[g] +"' class='removeGroup' src='/" + ctappdir + "/sms_relentless/img/closewnd.svg' title='Remove this group'></div>";
358
+				       }
359
+				   } else { var groupsfdb = ""; }
360
+
361
+				   if (allRestrictions[k].users) {
362
+				       var usersfdbpre = allRestrictions[k].users.split("|");
363
+				       var usersfdb = "";
364
+				       for (var u = 0; u < usersfdbpre.length; u++) {
365
+					    usersfdb += "<div class='selectedUsrs'>"+ usersfdbpre[u] +"<img id='rmvUsr-"+ usersfdbpre[u] +"' class='removeUser' src='/" + ctappdir + "/sms_relentless/img/closewnd.svg' title='Remove this user'></div>";
366
+				       }
367
+				   } else { var usersfdb = ""; }
368
+
369
+				   $("#phoneNmbrRestr").append("<tr><td><input type='text' class='restrAuthor' value='"+ allRestrictions[k].saved_by_dsplname +"' disabled></td><td><select id='rstphn-"+ k +"' class='restrPhoneNmbr' style='pointer-events:none'><option selected>"+ allRestrictions[k].phone_number +"</option></select></td><td><div id='rstgrp-"+ k +"' class='restrGroups'>"+ groupsfdb +"</div></td><td><div id='showGrps-"+ k +"' class='showAllGroups'><img src='/" + ctappdir + "/sms_relentless/img/group.svg' style='cursor:pointer' title='Show all groups'></div></td><td><div id='rstusr-"+ k +"' class='restrUsers'>"+ usersfdb +"</div></td><td><div id='showUsr-"+ k +"' class='showAllUsers'><img src='/" + ctappdir + "/sms_relentless/img/user.svg' style='cursor:pointer' title='Show all users'></div></td><td><img id='rmRow-"+ k +"' class='removeRow' src='/" + ctappdir + "/sms_relentless/img/closewnd.svg' title='Remove this row from the database' style='cursor:pointer;margin:6px 7px 0px 6px;'></td><td><input type='submit' id='rstsave-"+ k +"' class='saveRestrictions' value='Edit' title='Edit Row' /></td></tr>");
370
+			      }
371
+			      $("#phoneNmbrRestr").append("<div><img id='addRestrRow' src='/" + ctappdir + "/sms_relentless/img/add.svg' title='Add Row'></div>");
372
+			  }
373
+
374
+
375
+			  // Get the available phone numbers from all providers associated with the access keys entered on the Settings page
376
+			  $("#phoneNumberTh").addClass('icon-loading');
377
+			  var getnumbersUrl = OC.generateUrl("/apps/sms_relentless/user/getsmsnumbers");
378
+			  var numbersListItems = '';
379
+
380
+			  $.ajax({
381
+				  url: getnumbersUrl + '/' + userid,
382
+				  type: "POST",
383
+				  cache: false,
384
+				  processData: false,
385
+				  contentType: false,
386
+				  success: function(currentnmbrs) {
387
+
388
+					            $("#phoneNumberTh").removeClass('icon-loading');
389
+
390
+						    // Create a list with all the available phone numbers
391
+					            numbersListItems = "<option value='' selected>Select phone number</option>";
392
+
393
+						    $.each(currentnmbrs, function(key, indsmsnmb) {
394
+							   numbersListItems += "<option value='"+ indsmsnmb +"'>"+ indsmsnmb +"</option>";
395
+						    });
396
+
397
+						    if (restrNmb == 0) { var indRow = 0; } else { var indRow = parseInt(restrNmb + 1); }
398
+
399
+						    // Append the list of available phone numbers
400
+						    $("#rstphn-"+ indRow).empty();
401
+						    $("#rstphn-"+ indRow).append(numbersListItems);
402
+			
403
+				  },
404
+				  error: function() {
405
+					            $("#phoneNumberTh").removeClass('icon-loading'); 
406
+					            showAlert("Error while attempting to retrieve the available phone numbers!");
407
+				  }
408
+			  });
409
+
410
+
411
+			  function showLists() {
412
+
413
+			      // Append the list of available groups to the restrictions table
414
+			      $('[id^="showGrps-"]').click(function() {
415
+				 var crtnmbr = $(this).attr("id").replace("showGrps-", "");
416
+				 $("#grpL-"+ crtnmbr).remove();
417
+				 $("#showGrps-"+ crtnmbr).append("<div id='grpL-"+ crtnmbr +"' class='grpsList'>"+ grpsListItems +"</div>");
418
+				 $("#adminOverlay").remove();
419
+				 $("#app-content").append("<div id='adminOverlay'></div>");
420
+				 $("#adminOverlay").css({ "width" : parseInt($("#sms_relentless_adm").width() + 400) +"px", "height" : $("#sms_relentless_adm").height() +"px" });
421
+
422
+				 $("#adminOverlay").click(function() { 
423
+				    $("#adminOverlay").remove(); 
424
+				    $("#grpL-"+ crtnmbr).remove(); 
425
+				    $("#usrL-"+ crtnmbr).remove();
426
+				 });
427
+
428
+				 // Select a group
429
+				 $(".groupsList").click(function() {
430
+				    var slctdGrp = $(this).text();
431
+				    $("#grpL-"+ crtnmbr).remove();
432
+				    var addedTxtgrp = $("#rstgrp-"+ crtnmbr).text();
433
+
434
+				    if (addedTxtgrp.indexOf(slctdGrp) == -1) {
435
+					$("#rstgrp-"+ crtnmbr).append("<div class='selectedGrps'>"+ slctdGrp +"<img id='rmvGrp-"+ slctdGrp +"' class='removeGroup' src='/" + ctappdir + "/sms_relentless/img/closewnd.svg' title='Remove this group'></div>");
436
+				    } else { showAlert("That group has already been added!"); }
437
+
438
+				    // Remove a group from list
439
+				    $('[id^="rmvGrp-"]').click(function() {
440
+				       $(this).closest(".selectedGrps").remove();
441
+				    });
442
+				 });
443
+
444
+			      });
445
+
446
+			      // Append the list of available users to the restrictions table
447
+			      $('[id^="showUsr-"]').click(function() {
448
+
449
+				 var ctusrnmbr = $(this).attr("id").replace("showUsr-", "");
450
+				 $("#usrL-"+ ctusrnmbr).remove();
451
+				 $("#showUsr-"+ ctusrnmbr).append("<div id='usrL-"+ ctusrnmbr +"' class='usrsList'>"+ usersListItems +"</div>");
452
+				 $("#adminOverlay").remove();
453
+				 $("#app-content").append("<div id='adminOverlay'></div>");
454
+				 $("#adminOverlay").css({ "width" : parseInt($("#sms_relentless_adm").width() + 400) +"px", "height" : $("#sms_relentless_adm").height() +"px" });
455
+
456
+				 $("#adminOverlay").click(function() { 
457
+				    $("#adminOverlay").remove(); 
458
+				    $("#grpL-"+ ctusrnmbr).remove(); 
459
+				    $("#usrL-"+ ctusrnmbr).remove();
460
+				 });
461
+
462
+				 // Select a user
463
+				 $(".usersList").click(function() {
464
+				    var slctdUsr = $(this).text();
465
+				    var addedTxtusr = $("#rstusr-"+ ctusrnmbr).text();
466
+
467
+				    if (addedTxtusr.indexOf(slctdUsr) == -1) {
468
+					$("#rstusr-"+ ctusrnmbr).append("<div class='selectedUsrs'>"+ slctdUsr +"<img id='rmvUsr-"+ slctdUsr +"' class='removeUser' src='/" + ctappdir + "/sms_relentless/img/closewnd.svg' title='Remove this user'></div>");
469
+				    } else { showAlert("That user has already been added!"); }
470
+
471
+				    // Remove a user from list
472
+				    $('[id^="rmvUsr-"]').click(function() {
473
+				       $(this).closest(".selectedUsrs").remove();
474
+				    });
475
+				 });
476
+
477
+			      });
478
+
479
+			      // Remove a group from the list 
480
+			      $('[id^="rmvGrp-"]').click(function() {
481
+				 $(this).closest(".selectedGrps").remove();
482
+			      });
483
+
484
+			      // Remove a user from the list
485
+			      $('[id^="rmvUsr-"]').click(function() {
486
+				 $(this).closest(".selectedUsrs").remove();
487
+			      });
488
+
489
+			  }
490
+			  showLists();
491
+
492
+
493
+			  // Save the data
494
+			  function saveRestrRow() {
495
+
496
+			     $('[id^="rstsave-"]').unbind("click");
497
+			     $('[id^="rstsave-"]').click(function(event) {
498
+
499
+				 event.preventDefault();
500
+				 var crntrwnmbr = $(this).attr("id").replace("rstsave-", "");
501
+
502
+				 if ($(this).attr("value") == "Save") {
503
+
504
+				     var phoneNmbr = $("#rstphn-"+ crntrwnmbr).val();
505
+				     var slctdGroups = [];
506
+				     $("#rstgrp-"+ crntrwnmbr +" .selectedGrps").each(function() {
507
+					slctdGroups.push($(this).text());
508
+				     });
509
+				     var slctdUsers = [];
510
+				     $("#rstusr-"+ crntrwnmbr +" .selectedUsrs").each(function() {
511
+					slctdUsers.push($(this).text());
512
+				     });
513
+
514
+				     if (phoneNmbr != '') {
515
+
516
+				       if (slctdGroups.length > 0 || slctdUsers.length > 0) {
517
+
518
+					 var saveRestrUrl = OC.generateUrl('/apps/sms_relentless/user/updatenumberrestrictions');
519
+
520
+					 var datatosend = { 
521
+					      userId: userid,
522
+					      savedByDsplname: crntadmDispName,
523
+					      phoneNumber: phoneNmbr,
524
+					      groups: slctdGroups,
525
+					      users: slctdUsers
526
+					 };
527
+
528
+					 $.ajax({
529
+					   method: 'PUT',
530
+					   url: saveRestrUrl + '/' + userid,
531
+					   contentType: 'application/json',
532
+					   data: JSON.stringify(datatosend),
533
+					   success: function(messagetosend) {
534
+					                if (messagetosend == 'success') {
535
+					                    showAlert('The restrictions have been successfully saved to the database!');
536
+					                } else {
537
+					                    showAlert('Error while trying to save the restrictions!');
538
+					                }
539
+					   },
540
+					   error: function() {
541
+							showAlert('Error while attempting to save the restrictions! You can check the Nextcloud log to find more details about this issue.');
542
+					   }
543
+					 });
544
+
545
+				       } else { showAlert("You must select at least a group or a user in order to restrict access to a phone number."); return; }
546
+
547
+				     } else { showAlert("Please select a phone number!"); return; }
548
+
549
+				     $(this).attr("value", "Edit");
550
+
551
+				} else {
552
+
553
+				     $("#rstsave-"+ crntrwnmbr).attr("value", "Save");
554
+				}
555
+
556
+			     });
557
+			  }
558
+			  saveRestrRow();
559
+
560
+			  // Remove a row
561
+			  function removeRestrRow() {
562
+
563
+			       $('[id^="rmRow-"]').click(function() {
564
+
565
+				  var slctRowRmv = $(this).attr("id").replace("rmRow-", "");
566
+				  var crntPhNmbr = $("#rstphn-"+ slctRowRmv).val();
567
+
568
+				  confirmAlert("Do you really want to remove this row from the database ?");
569
+
570
+				  $("#confirmCancel").click(function() { $("#alertMsgOverlay").remove(); $("#alertConfMessage").remove(); });
571
+
572
+				  $("#confirmOk").click(function() {
573
+
574
+				      $("#alertMsgOverlay").remove();
575
+				      $("#alertConfMessage").remove();
576
+
577
+				      var rmvRestrUrl = OC.generateUrl('/apps/sms_relentless/user/removenumberrestrictions');
578
+				      $.ajax({
579
+					   url: rmvRestrUrl + '/' + userid,
580
+					   method: "POST",
581
+					   dataType: "text",
582
+					   data: { phoneNumber: crntPhNmbr },
583
+					   success: function(delresult) {
584
+
585
+					                     if (delresult.indexOf("success") > -1) {
586
+					                         showAlert("The restriction has been removed successfully!");
587
+					                         $("#rstphn-"+ slctRowRmv).closest("tr").remove();
588
+					                     } else {
589
+					                         showAlert("Error while trying to remove restriction data!");
590
+					                     }
591
+					   },
592
+					   error: function() { showAlert("Error while attempting to remove restriction data! You can check the Nextcloud log to find more details about this issue."); }
593
+				       });
594
+				  });
595
+			       });
596
+			  }
597
+			  removeRestrRow();
598
+
599
+			  // Add a new row
600
+			  $("#addRestrRow").click(function() {
601
+			      if ($("#phoneNmbrRestr").find("tr:last-child").find(".restrPhoneNmbr").length > 0) {
602
+				  var lastrstAuth = $("#phoneNmbrRestr").find("tr:last-child").find(".restrPhoneNmbr").attr("id").replace("rstphn-", "");
603
+				  var indRowAdd = parseInt(lastrstAuth + 1);
604
+			      } else { var indRowAdd = 0; }
605
+			      $("#phoneNmbrRestr").append("<tr><td><input type='text' class='restrAuthor' value='"+ crntadmDispName +"' disabled></td><td><select id='rstphn-"+ indRowAdd +"' class='restrPhoneNmbr'>"+ numbersListItems +"</select></td><td><div id='rstgrp-"+ indRowAdd +"' class='restrGroups'></div></td><td><div id='showGrps-"+ indRowAdd +"' class='showAllGroups'><img src='/" + ctappdir + "/sms_relentless/img/group.svg' style='cursor:pointer' title='Show all groups'></div></td><td><div id='rstusr-"+ indRowAdd +"' class='restrUsers'></div></td><td><div id='showUsr-"+ indRowAdd +"' class='showAllUsers'><img src='/" + ctappdir + "/sms_relentless/img/user.svg' style='cursor:pointer' title='Show all users'></div></td><td><img id='rmRow-"+ indRowAdd +"' class='removeRow' src='/" + ctappdir + "/sms_relentless/img/closewnd.svg' title='Remove this row from the database' style='cursor:pointer;margin:6px 7px 0px 6px;'></td><td><input type='submit' id='rstsave-"+ indRowAdd +"' class='saveRestrictions' value='Save' title='Save Row' /></td></tr>");
606
+			      showLists();
607
+			      saveRestrRow();
608
+			      removeRestrRow();
609
+
610
+			      // Check if the same phone number has been already restricted
611
+			      $("#rstphn-"+ indRowAdd).change(function() {
612
+				 var selectedPhNmbr = $("#rstphn-"+ indRowAdd).val();
613
+				 var allPHoneRestr = $("#phoneNmbrRestr").find("tr").find(".restrPhoneNmbr");
614
+				 var phNmbrChck = 0;
615
+				 allPHoneRestr.each(function() {
616
+				    var slctdphnmbr = ($(this).val())? $(this).val() : $(this).text();
617
+				    if (selectedPhNmbr == slctdphnmbr) { phNmbrChck++; }
618
+				 });
619
+
620
+				 if (phNmbrChck == 2) {
621
+				     showAlert("This phone number is already in the list of restricted phone numbers. Please edit its own row, or choose a different phone number to restrict access to.");
622
+				     $(this).val('');
623
+				     return;
624
+				 }
625
+			      });
626
+			  });
627
+
628
+		     },
629
+		     error: function() {
630
+				showAlert('Error while getting the admin settings! You can check the Nextcloud log to find more details about this issue.');
631
+		     }
632
+		  });
633
+
634
+
635
+
636
+		  // Save admin settings
637
+		  function randomStr(strlength) {
638
+			var fintext = "";
639
+			var keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
640
+			for (var i = 0; i < strlength; i++) {
641
+			     fintext += keyspace.charAt(Math.floor(Math.random() * keyspace.length));
642
+			}
643
+			return fintext;
644
+		  }
645
+
646
+		  $("#generate_tel_rcpt").on("click", function(event) {
647
+
648
+		     var teltokenrec = randomStr(70);
649
+		     var telnyxwhurlrec = window.location.origin + OC.generateUrl('/apps/sms_relentless/api/recsmstel?telrecparam=') + teltokenrec;
650
+
651
+		     $("#telapi_url_rec").val(telnyxwhurlrec);
652
+		  });
653
+
654
+		  $("#copyToClipboardtel").on("click", function(event) {
655
+		     var $tempEl = $("<input>");
656
+		     $("body").append($tempEl);
657
+		     $tempEl.val($("#telapi_url_rec").val()).select();
658
+		     document.execCommand("Copy");
659
+		     $tempEl.remove();
660
+		     showAlert("The link has been copied to your clipboard!");
661
+		  });
662
+
663
+		  $("#generate_tel_delrcpt").on("click", function(event) {
664
+
665
+		     var teltoken = randomStr(70);
666
+		     var telnyxwhurl = window.location.origin + OC.generateUrl('/apps/sms_relentless/api/recdeliverytel?teldrparam=') + teltoken;
667
+
668
+		     $("#telapi_url").val(telnyxwhurl);
669
+		  });
670
+
671
+		  $("#generate_nex_rcpt").on("click", function(event) {
672
+
673
+		     var plivotokenrec = randomStr(70);
674
+		     var plivowhurlrec = window.location.origin + OC.generateUrl('/apps/sms_relentless/api/recsmsnex?plivorecparam=') + plivotokenrec;
675
+
676
+		     $("#nexapi_url_rec").val(plivowhurlrec);
677
+		  });
678
+
679
+		  $("#copyToClipboardnex").on("click", function(event) {
680
+		     var $tempElpl = $("<input>");
681
+		     $("body").append($tempElpl);
682
+		     $tempElpl.val($("#nexapi_url_rec").val()).select();
683
+		     document.execCommand("Copy");
684
+		     $tempElpl.remove();
685
+		     showAlert("The link has been copied to your clipboard!");
686
+		  });
687
+
688
+		  $("#generate_nex_delrcpt").on("click", function(event) {
689
+
690
+		     var plivotoken = randomStr(70);
691
+		     var plivodrwhurl = window.location.origin + OC.generateUrl('/apps/sms_relentless/api/recdeliverynex?plivodrparam=') + plivotoken;
692
+
693
+		     $("#nexapi_url").val(plivodrwhurl);
694
+		  });
695
+
696
+		  $("#generate_twil_rcpt").on("click", function(event) {
697
+
698
+		     var twiltokenrec = randomStr(35);
699
+		     var twilwhurlrec = window.location.origin + OC.generateUrl('/apps/sms_relentless/api/recsmstwil?twilrecparam=') + twiltokenrec;
700
+
701
+		     $("#twilapi_url_rec").val(twilwhurlrec);
702
+		  });
703
+
704
+		  $("#copyToClipboardtwil").on("click", function(event) {
705
+		     var $tempElpl = $("<input>");
706
+		     $("body").append($tempElpl);
707
+		     $tempElpl.val($("#twilapi_url_rec").val()).select();
708
+		     document.execCommand("Copy");
709
+		     $tempElpl.remove();
710
+		     showAlert("The link has been copied to your clipboard!");
711
+		  });
712
+
713
+		  $("#generate_twil_delrcpt").on("click", function(event) {
714
+
715
+		     var twiltoken = randomStr(35);
716
+		     var twildrwhurl = window.location.origin + OC.generateUrl('/apps/sms_relentless/api/recdeliverytwil?twildrparam=') + twiltoken;
717
+
718
+		     $("#twilapi_url").val(twildrwhurl);
719
+		  });
720
+
721
+		  $("#generate_flow_rcpt").on("click", function(event) {
722
+
723
+		     var flowtokenrec = randomStr(70);
724
+		     var flowwhurlrec = window.location.origin + OC.generateUrl('/apps/sms_relentless/api/recsmsflow?flowrecparam=') + flowtokenrec;
725
+
726
+		     $("#flowapi_url_rec").val(flowwhurlrec);
727
+		  });
728
+
729
+		  $("#copyToClipboardflow").on("click", function(event) {
730
+		     var $tempElpl = $("<input>");
731
+		     $("body").append($tempElpl);
732
+		     $tempElpl.val($("#flowapi_url_rec").val()).select();
733
+		     document.execCommand("Copy");
734
+		     $tempElpl.remove();
735
+		     showAlert("The link has been copied to your clipboard!");
736
+		  });
737
+
738
+		  $("#generate_flow_delrcpt").on("click", function(event) {
739
+
740
+		     var flowtoken = randomStr(70);
741
+		     var flowdrwhurl = window.location.origin + OC.generateUrl('/apps/sms_relentless/api/recdeliveryflow?flowdrparam=') + flowtoken;
742
+
743
+		     $("#flowapi_url").val(flowdrwhurl);
744
+		  });
745
+
746
+		  // Add group icons
747
+		  $(".srGroupImg").each(function() {
748
+		     $(this).attr("src", "/" + ctappdir + "/sms_relentless/img/group.svg");
749
+		  });
750
+
751
+		  // Add user icons
752
+		  $(".srUserImg").each(function() {
753
+		     $(this).attr("src", "/" + ctappdir + "/sms_relentless/img/user.svg");
754
+		  });
755
+
756
+		  $("#save_admin_settings").on("click", function(event) {
757
+
758
+		    event.preventDefault();
759
+		    OC.msg.startAction('#smsr_save_msg', t('sms_relentless', 'Saved'));
760
+
761
+		    var baseUrlsv = OC.generateUrl('/apps/sms_relentless/user/updateadminsettings');
762
+
763
+		    var showallmsgs = 0;
764
+		    if ($("#showallmessages").is(':checked')) {
765
+			showallmsgs = 1;
766
+		    }
767
+
768
+		    var telsenderinit = $("#tel_sender_name").val();
769
+		    var telsenderproc = telsenderinit.replace(/[^A-Za-z 0-9]/g, '');
770
+
771
+		    var nexsenderinit = $("#nex_sender_name").val();
772
+		    var nexsenderproc = nexsenderinit.replace(/[^A-Za-z 0-9]/g, '');
773
+
774
+		    var twilsenderinit = $("#twil_sender_name").val();
775
+		    var twilsenderproc = twilsenderinit.replace(/[^A-Za-z 0-9]/g, '');
776
+
777
+		    var datatosave = {
778
+				      userId: userid,
779
+				      telapiKey: $("#telapi_key").val(),
780
+				      telPubKey: $("#tel_pub_key").val(),
781
+				      telapiUrlRec: $("#telapi_url_rec").val(),
782
+				      telapiUrl: $("#telapi_url").val(),
783
+				      messagingProfileId: $("#messaging_profile_id").val(),
784
+				      nexapiKey: $("#nexapi_key").val(),
785
+				      nexapiSecret: $("#nexapi_secret").val(),
786
+				      nexapiUrlRec: $("#nexapi_url_rec").val(),
787
+				      nexapiUrl: $("#nexapi_url").val(),
788
+				      twilapiKey: $("#twilapi_key").val(),
789
+				      twilapiSecret: $("#twilapi_secret").val(),
790
+				      twilapiUrlRec: $("#twilapi_url_rec").val(),
791
+				      twilapiUrl: $("#twilapi_url").val(),
792
+				      flowapiKey: $("#flowapi_key").val(),
793
+				      flowapiSecret: $("#flowapi_secret").val(),
794
+				      flowapiUrlRec: $("#flowapi_url_rec").val(),
795
+				      flowapiUrl: $("#flowapi_url").val(),
796
+				      telSenderName: telsenderproc,
797
+				      nexSenderName: nexsenderproc,
798
+				      twilSenderName: twilsenderproc,
799
+				      showAllMessages: showallmsgs
800
+		    };
801
+
802
+
803
+		    $.ajax({
804
+		       method: 'PUT',
805
+		       url: baseUrlsv + '/' + userid,
806
+		       contentType: 'application/json',
807
+		       data: JSON.stringify(datatosave),
808
+		       success: function() {
809
+		       },
810
+		       error: function() {
811
+			    showAlert('Error while attempting to save the settings! You can check the Nextcloud log to find more details about this issue.');
812
+		       }
813
+		    });
814
+
815
+		  });
816
+
817
+		  function showAlert(alertText) {
818
+
819
+		     let alertwnd = "<div id='alertMessage'>";
820
+		     alertwnd += "<a id='closeAlertWnd' title='Close this window'></a>";
821
+		     alertwnd += "<div id='alertTextWrap'>"+ alertText +"</div>";
822
+		     alertwnd += "<input type='submit' id='alertOk' value='OK'>";
823
+		     alertwnd += "</div>";
824
+
825
+		     $("#content").append("<div id='alertMsgOverlay'></div>");
826
+		     $("#content").append(alertwnd);
827
+
828
+		     let topDist = parseInt((window.innerHeight / 2).toFixed(2) - 152) +"px";
829
+		     let leftDist = parseInt((window.innerWidth / 2).toFixed(2) - 150) +"px";
830
+		     $("#alertMessage").css({ "top" : topDist, "left" : leftDist });
831
+
832
+		     $("#closeAlertWnd").click(function() { $("#alertMsgOverlay").remove(); $("#alertMessage").remove(); });
833
+		     $("#alertMsgOverlay").click(function() { $("#alertMsgOverlay").remove(); $("#alertMessage").remove(); });
834
+		     $("#alertOk").click(function() { $("#alertMsgOverlay").remove(); $("#alertMessage").remove(); });
835
+		  }
836
+
837
+		  function confirmAlert(alertText) {
838
+
839
+		     $("#alertMsgOverlay").remove();
840
+		     $("#alertConfMessage").remove();
841
+
842
+		     let alertwndcf = "<div id='alertConfMessage'>";
843
+		     alertwndcf += "<a id='closeAlertWndcf' title='Close this window'></a>";
844
+		     alertwndcf += "<div id='alertTextWrap'>"+ alertText +"</div>";
845
+		     alertwndcf += "<div id='cancelOkWrap'><input type='submit' id='confirmCancel' value='Cancel'>";
846
+		     alertwndcf += "<input type='submit' id='confirmOk' value='OK'></div>";
847
+		     alertwndcf += "</div>";
848
+
849
+		     $("#content").append("<div id='alertMsgOverlay'></div>");
850
+		     $("#content").append(alertwndcf);
851
+
852
+		     let topDist = parseInt((window.innerHeight / 2).toFixed(2) - 152) +"px";
853
+		     let leftDist = parseInt((window.innerWidth / 2).toFixed(2) - 150) +"px";
854
+		     $("#alertConfMessage").css({ "top" : topDist, "left" : leftDist });
855
+
856
+		     $("#closeAlertWndcf").click(function() { $("#alertMsgOverlay").remove(); $("#alertConfMessage").remove(); });
857
+		     $("#alertMsgOverlay").click(function() { $("#alertMsgOverlay").remove(); $("#alertConfMessage").remove(); });
858
+		  }
859
+
860
+
861
+     },
862
+     error: function(appdirfdb) {
863
+                alert("An error occurred while getting the app's directory. You can check the Nextcloud log to find more details about this issue.");
864
+     }
865
+   });
866
+
867
+});
0 868
new file mode 100644
... ...
@@ -0,0 +1,1642 @@
1
+/**
2
+ * @copyright 2021 Double Bastion LLC <www.doublebastion.com>
3
+ *
4
+ * @author Double Bastion LLC
5
+ *
6
+ * @license GNU AGPL version 3 or any later version
7
+ *
8
+ * This program is free software; you can redistribute it and/or
9
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
10
+ * License as published by the Free Software Foundation; either
11
+ * version 3 of the License, or any later version.
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
17
+ *
18
+ * You should have received a copy of the GNU Affero General Public
19
+ * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
+ *
21
+ */
22
+
23
+  var userid = "<?php p($userId); ?>";
24
+  var charcolorthr = 160;
25
+  var textread = '';
26
+  var providerUsed = '';
27
+  var receiversNumbers = [];
28
+  var waittime = 1000;
29
+  var selectedid = '';
30
+  var isMMS = 0;
31
+  var n = 1;
32
+  var textsizekb = 0;
33
+  var uploadedtomms = [];
34
+  var msgtotalflsize = 0;
35
+  var readtxtfile = [];
36
+  var readjpg = [];
37
+  var readpng = [];
38
+  var readgif = [];
39
+  var readbmp = [];
40
+  var readtif = [];
41
+  var readmp4 = [];
42
+  var chosenProvider = '';
43
+  var chosenProvFullName = '';
44
+  var infonotecontent = '';
45
+  var validExtensions = [];
46
+  var maximumsize = 750;
47
+  var maxsizenonimage = 600;
48
+  var maximumfilenumber = 10;
49
+  var maximumsizeinit = 750;
50
+
51
+  // Adjust the path, so that the uploaded pdf files can be previewed while Nextcloud is served on a subdomain or on a subdirectory, by Nginx or by Apache
52
+  var locHref = window.location.href;
53
+  var pathSplit = locHref.split('/');
54
+  var firstPathEl = '';
55
+  if (pathSplit.length == 7) { firstPathEl = '/' + pathSplit[3]; }
56
+
57
+
58
+  // Get the available phone numbers associated with the API keys saved on the Settings page
59
+  $("#smsnumbersdiv").addClass('icon-loading');
60
+
61
+  var getsmsnumbersUrl = OC.generateUrl("/apps/sms_relentless/user/getsmsnumbers");
62
+
63
+  $.ajax({
64
+          url: getsmsnumbersUrl + '/' + userid,
65
+          type: "POST",
66
+          data: { userid: userid },
67
+          cache: false,
68
+          processData: false,
69
+          contentType: false,
70
+          success: function(currentnmbrs) {
71
+
72
+                     $('#currentsmsnmbrs').empty();
73
+
74
+                     if (currentnmbrs.length > 1) {
75
+
76
+                         $('#currentsmsnmbrs').append("<option value='' class='optselectsmsnb' selected disabled>Choose an ID</option>");
77
+
78
+                         $.each(currentnmbrs, function(key, valsmsnmb) {
79
+                                $('#currentsmsnmbrs').append("<option value='"+ valsmsnmb +"' class='optselectsmsnb'>"+ valsmsnmb +"</option>");
80
+                         });
81
+
82
+                         // Append the available providers to the 'see balance' drop-down list
83
+                         var providerNm = [];
84
+                         for (var n = 0; n < currentnmbrs.length; n++) {
85
+
86
+                              var provfirstchr = currentnmbrs[n].split(": ")[0];
87
+                              if (provfirstchr == "Tx") {
88
+                                  if (providerNm.indexOf("Telnyx") === -1) {
89
+                                      providerNm.push("Telnyx");
90
+                                      $("#smsprovider").append("<option value='Telnyx' class='selectsmsprov'>Telnyx</option>");
91
+                                  }
92
+                              } else if (provfirstchr == "Pl") {
93
+                                  if (providerNm.indexOf("Plivo") === -1) {
94
+                                      providerNm.push("Plivo");
95
+                                      $("#smsprovider").append("<option value='Plivo' class='selectsmsprov'>Plivo</option>");
96
+                                  }
97
+                              } else if (provfirstchr == "Tw") {
98
+                                  if (providerNm.indexOf("Twilio") === -1) {
99
+                                      providerNm.push("Twilio");
100
+                                      $("#smsprovider").append("<option value='Twilio' class='selectsmsprov'>Twilio</option>");
101
+                                  }
102
+                              } else if (provfirstchr == "Fl") {
103
+                                  if (providerNm.indexOf("Flowroute") === -1) {
104
+                                      providerNm.push("Flowroute");
105
+                                      $("#smsprovider").append("<option value='Flowroute' class='selectsmsprov'>Flowroute</option>");
106
+                                  }
107
+                              }
108
+                         }
109
+
110
+                     } else if (currentnmbrs.length == 1) {
111
+
112
+                                $('#currentsmsnmbrs').append("<option value='"+ currentnmbrs[0] +"' class='optselectsmsnb' selected disabled>"+ currentnmbrs[0] +"</option>");
113
+
114
+                                selectedid = currentnmbrs[0];
115
+
116
+                                var unqprovider = currentnmbrs[0].split(": ")[0];
117
+
118
+                                if (unqprovider == 'Tx') {
119
+
120
+					  validExtensions = ["jpg", "jpeg", "png", "gif", "mp3", "ogg", "amr", "mp4", "3gpp", "pdf", "vcf", "vcard", "txt"];
121
+					  // Maximum size of message text + files in KB
122
+					  maximumsize = 1024;
123
+					  maximumsizeinit = 1024;
124
+					  maxsizenonimage = 600;
125
+					  maximumfilenumber = 10;
126
+					  chosenProvFullName = "Telnyx";
127
+					  infonotecontent = "To send an MMS, you can upload media files or pick them from Nextcloud. You can add up to 10 files. For Telnyx, if you send only jpeg/jpg, png \
128
+						             or gif files, the size of all the files plus the size of the text should be \
129
+						             <a href='https://support.telnyx.com/en/articles/4450150-faqs-about-mms-at-telnyx' style='color:#1b60ba' target='_blank' \
130
+						             rel='noreferrer noopener'>1024 KB</a> or less. If you send files of other formats, the total size of the files plus the size of the text should \
131
+						             be 600 KB or less. Allowed formats are jpeg/jpg, png, gif, mp3, ogg, amr, mp4, 3gpp, pdf, vcf, vcard and txt. By default, Telnyx accounts are \
132
+						             limited to <a href='https://support.telnyx.com/en/articles/3102823-mms-sending-and-receiving' style='color:#1b60ba' target='_blank' \
133
+						             rel='noreferrer noopener'>1 MMS message per second</a>. Deliverability of MMS messages depends on the carrier and device of the receiver. \
134
+						             Carriers can reject MMS messages with files exceeding a certain size. The best deliverability is achieved when sending jpeg/jpg, png or \
135
+						             gif files, with a total message size of 600 KB or less. Telnyx allows sending MMS messages only from US or Canadian phone numbers to other US \
136
+						             or Canadian phone numbers. Although all the specified file types can be added to the MMS, only the most common media file types (jpeg/jpg, png, \
137
+						             gif, mp4, ogg, etc.) can be previewed in the adjoining pane.";
138
+					  $("#tooltiptextfourth").html(infonotecontent);
139
+
140
+                                          // Append 'Telnyx' to the 'see balance' drop-down list
141
+                                          $("#smsprovider").append("<option value='Telnyx' class='selectsmsprov'>Telnyx</option>");
142
+
143
+                                } else if (unqprovider == 'Pl') {
144
+
145
+					  validExtensions = ["jpg", "jpeg", "png", "gif", "bmp", "wav", "wave", "mp4", "amr", "mpg", "mpeg", "3gpp", "3gpp2", "vcf", "vcard", "x-vcard", "ics", "ical", "ifb", 
146
+						             "icalendar", "csv", "txt", "pdf", "xls"];
147
+					  // Maximum size of message text + files in KB
148
+					  maximumsize = 5120;
149
+					  maximumsizeinit = 5120;
150
+					  maxsizenonimage = 600;
151
+					  maximumfilenumber = 10;
152
+					  chosenProvFullName = "Plivo";
153
+					  infonotecontent = "To send an MMS, you can upload media files or pick them from Nextcloud. You can add up to 10 files. For Plivo, if you send only jpeg/jpg, png \
154
+						             or gif files, the size of all the files plus the size of the text should be \
155
+						             <a href='https://support.plivo.com/hc/en-us/articles/360042280091-What-are-the-MMS-upload-size-limits-and-file-restrictions-' \
156
+						             style='color:#1b60ba' target='_blank' rel='noreferrer noopener'>5120 KB</a> or less. If you send files of other formats, the total size \
157
+						             of the files plus the size of the text should be 600 KB or less. <a href='https://support.plivo.com/hc/en-us/articles/360042273051' \
158
+						             style='color:#1b60ba' target='_blank' rel='noreferrer noopener'>Allowed formats</a> are jpeg/jpg, png, gif, bmp, wav/wave, mp4, amr, mpg, mpeg, 3gpp, \
159
+						             3gpp2, vcf, vcard, x-vcard, ics, ical, ifb, icalendar, csv, txt, pdf and xls. Deliverability of MMS messages depends on the carrier and \
160
+						             device of the receiver. Carriers can reject MMS messages with files exceeding a certain size. The best deliverability is \
161
+						             achieved when sending jpeg/jpg, png or gif files, with a total message size of 600 KB or less. Plivo allows sending MMS messages \
162
+						             only from US or Canadian phone numbers to other US or Canadian phone numbers. Although all the specified file types can be added to the MMS, \
163
+						             only the most common media file types (jpeg/jpg, png, gif, wav/wave, mp4, etc.) can be previewed in the adjoining pane.";
164
+					  $("#tooltiptextfourth").html(infonotecontent);
165
+
166
+                                          // Append 'Plivo' to the 'see balance' drop-down list
167
+                                          $("#smsprovider").append("<option value='Plivo' class='selectsmsprov'>Plivo</option>");
168
+
169
+                                } else if (unqprovider == 'Tw') {
170
+
171
+					  validExtensions = ["jpg", "jpeg", "png", "gif", "bmp", "tiff", "tif", "au", "snd", "l16", "wav", "wave", "aiff", "pcm", "mp4", "ogg", "ra", "ram", "3gpp", 
172
+						             "3gpp2", "ac3", "webm", "amr", "mpg", "mpeg", "mov", "qt", "h261", "h263", "h264", "vcf", "vcard", "x-vcard", "csv", "rtf", "ics", "ical", "ifb", 
173
+						             "icalendar", "directory", "pdf", "pkpass"];
174
+					  // Maximum size of message text + files in KB
175
+					  maximumsize = 5120;
176
+					  maximumsizeinit = 5120;
177
+					  maxsizenonimage = 600;
178
+					  maximumfilenumber = 10;
179
+					  chosenProvFullName = "Twilio";
180
+					  infonotecontent = "To send an MMS, you can upload media files or pick them from Nextcloud. You can add up to 10 files. For Twilio, if you send only jpeg/jpg, png \
181
+						             or gif files, the size of all the files plus the size of the text should be \
182
+						             <a href='https://support.twilio.com/hc/en-us/articles/360018832773-Twilio-Programmable-SMS-Supported-File-Types-and-Size-Limits-for-MMS-Media-Messages' \
183
+						             style='color:#1b60ba' target='_blank' rel='noreferrer noopener'>5120 KB</a> or less. If you send files of other formats, the total size \
184
+						             of the files plus the size of the text should be 600 KB or less. <a href='https://www.twilio.com/docs/sms/accepted-mime-types' \
185
+						             style='color:#1b60ba' target='_blank' rel='noreferrer noopener'>Allowed formats</a> are jpeg/jpg, png, gif, bmp, tiff/tif, au, snd, l16, \
186
+						             wav/wave, aiff, pcm, mp4, ogg, ra, ram, 3gpp, 3gpp2, ac3, webm, amr, mpg, mpeg, mov, qt, h261, h263, h264, vcf, vcard, x-vcard, csv, rtf, ics, \
187
+						             ical, ifb, icalendar, directory, pdf and pkpass. Deliverability of MMS messages depends on the carrier and device of the receiver. Carriers \
188
+						             can reject MMS messages with files exceeding a certain size. The best deliverability is achieved when sending jpeg/jpg, png or gif files, \
189
+						             with a total message size of 600 KB or less. Twilio allows sending MMS messages from US or Canadian phone numbers to other US or Canadian phone \
190
+						             numbers. However, MMS messages sent internationally will be converted to SMS messages with URL links to the included files. Although all the \
191
+						             specified file types can be added to the MMS, only the most common media file types (jpeg/jpg, png, gif, wav/wave, mp4, ogg, etc.) can be \
192
+						             previewed in the adjoining pane."
193
+					  $("#tooltiptextfourth").html(infonotecontent);
194
+
195
+                                          // Append 'Twilio' to the 'see balance' drop-down list
196
+                                          $("#smsprovider").append("<option value='Twilio' class='selectsmsprov'>Twilio</option>");
197
+
198
+                                } else if (unqprovider == 'Fl') {
199
+
200
+					  validExtensions = ["jpg", "jpeg", "png", "gif", "bmp", "3gp", "mp4", "avi", "amr", "midi", "wav", "wave", "ac3", "mp3"];
201
+					  // Maximum size of message text + files in KB
202
+					  maximumsize = 750;
203
+					  maximumsizeinit = 750;
204
+					  maxsizenonimage = 600;
205
+					  maximumfilenumber = 10;
206
+					  chosenProvFullName = "Flowroute";
207
+					  infonotecontent = "To send an MMS, you can upload media files or pick them from Nextcloud. You can add up to 10 files. For Flowroute, if you send only jpeg/jpg, \
208
+							     png or gif files, the size of all the files plus the size of the text should be \
209
+							     <a href='https://developer.flowroute.com/api/messages/v2.1/send-an-mms/' style='color:#1b60ba' target='_blank' \
210
+							     rel='noreferrer noopener'>750 KB</a> or less. If you send files of other formats, the total \
211
+							     size of the files plus the size of the text should be 600 KB or less. \
212
+							     <a href='https://support.flowroute.com/937402-What-file-types-does-Flowroute-MMS-support' style='color:#1b60ba' target='_blank' \
213
+							     rel='noreferrer noopener'>Allowed formats</a> are jpeg/jpg, png, gif, bmp, 3gp, mp4, avi, amr, midi, wav/wave, ac3 and mp3. Flowroute accounts are \
214
+							     limited to <a href='https://developer.flowroute.com/docs/sms-mms-best-practices/#sending-and-receiving-limitations' style='color:#1b60ba' \
215
+							     target='_blank' rel='noreferrer noopener'>1 MMS message per second</a>. Deliverability of MMS messages depends on the carrier and device \
216
+							     of the receiver. Carriers can reject MMS messages with files exceeding a certain size. The best deliverability is achieved when sending \
217
+							     jpeg/jpg, png or gif files, with a total message size of 600 KB or less. Flowroute allows sending MMS messages only from US or Canadian phone \
218
+							     numbers to other US or Canadian phone numbers. Although all the specified file types can be added to the MMS, only the most common media file \
219
+							     types (jpeg/jpg, png, gif, wav/wave, mp4, etc.) can be previewed in the adjoining pane."
220
+					  $("#tooltiptextfourth").html(infonotecontent);
221
+
222
+                                          // Append 'Flowroute' to the 'see balance' drop-down list
223
+                                          $("#smsprovider").append("<option value='Flowroute' class='selectsmsprov'>Flowroute</option>");
224
+                                }
225
+                     } else {
226
+                                $('#currentsmsnmbrs').append("<option value='' class='optselectsmsnb' selected disabled>No IDs</option>");
227
+                     }
228
+
229
+                     $("#smsnumbersdiv").removeClass('icon-loading');
230
+          }
231
+  });
232
+
233
+  // Clean the SMS_Relentless/temp_files directory
234
+  function cleanTempDirectory() {
235
+
236
+     var cleanflUrl = OC.generateUrl("/apps/sms_relentless/user/cleantempdir");
237
+
238
+     $.ajax({
239
+          url: cleanflUrl + '/' + userid,
240
+          type: "POST",
241
+          data: { userid: userid },
242
+          cache: false,
243
+          processData: false,
244
+          contentType: false
245
+     });
246
+  }
247
+  cleanTempDirectory();
248
+
249
+  // Clean the SMS_Relentless/multiple_recipients directory
250
+  function cleanMultRecDirectory() {
251
+
252
+     var cleanflUrl = OC.generateUrl("/apps/sms_relentless/user/cleanmultrecdir");
253
+
254
+     $.ajax({
255
+          url: cleanflUrl + '/' + userid,
256
+          type: "POST",
257
+          data: { userid: userid },
258
+          cache: false,
259
+          processData: false,
260
+          contentType: false
261
+     });
262
+  }
263
+  cleanMultRecDirectory();
264
+
265
+  // Check the available balance
266
+  $("#smsprovider").on("change", function () {
267
+
268
+     var provider = $('#smsprovider :selected').val();
269
+
270
+     if (provider == "Telnyx") {
271
+
272
+        var gettelbalance = function() {
273
+
274
+          $('#currentbalance').addClass('icon-loading');
275
+
276
+          var gettelbalanceUrl = OC.generateUrl("/apps/sms_relentless/user/getbalancetel");
277
+
278
+          $.ajax({
279
+              url: gettelbalanceUrl + '/' + userid,
280
+              type: "POST",
281
+              data: { userid: userid },
282
+              cache: false,
283
+              processData: false,
284
+              contentType: false,
285
+              success: function(currentbalancetel) {
286
+
287
+                     $('#currentbalance').empty();
288
+                     $('#currentbalance').text(currentbalancetel);
289
+                     $('#currentbalance').removeClass('icon-loading');
290
+              }
291
+          });
292
+        }
293
+
294
+        gettelbalance();
295
+
296
+     } else if (provider == "Plivo") {
297
+
298
+          var getnexbalance = function() {
299
+
300
+            $('#currentbalance').addClass('icon-loading');
301
+
302
+            var getnexbalanceUrl = OC.generateUrl("/apps/sms_relentless/user/getbalancenex");
303
+
304
+            $.ajax({
305
+                url: getnexbalanceUrl + '/' + userid,
306
+                type: "POST",
307
+                data: { userid: userid },
308
+                cache: false,
309
+                processData: false,
310
+                contentType: false,
311
+                success: function(currentbalancenex) {
312
+
313
+                     $('#currentbalance').empty();
314
+                     $('#currentbalance').text(currentbalancenex);
315
+                     $('#currentbalance').removeClass('icon-loading');
316
+                }
317
+            });
318
+          }
319
+
320
+          getnexbalance();
321
+
322
+     } else if (provider == "Twilio") {
323
+
324
+          var gettwilbalance = function() {
325
+
326
+            $('#currentbalance').addClass('icon-loading');
327
+
328
+            var gettwilbalanceUrl = OC.generateUrl("/apps/sms_relentless/user/getbalancetwil");
329
+
330
+            $.ajax({
331
+                url: gettwilbalanceUrl + '/' + userid,
332
+                type: "POST",
333
+                data: { userid: userid },
334
+                cache: false,
335
+                processData: false,
336
+                contentType: false,
337
+                success: function(currentbalancetwil) {
338
+
339
+                     $('#currentbalance').empty();
340
+                     $('#currentbalance').text(currentbalancetwil);
341
+                     $('#currentbalance').removeClass('icon-loading');
342
+                }
343
+            });
344
+          }
345
+
346
+          gettwilbalance();
347
+
348
+     } else if (provider == "Flowroute") {
349
+
350
+          var getflowbalance = function() {
351
+
352
+            $('#currentbalance').addClass('icon-loading');
353
+
354
+            var getflowbalanceUrl = OC.generateUrl("/apps/sms_relentless/user/getbalanceflow");
355
+
356
+            $.ajax({
357
+                url: getflowbalanceUrl + '/' + userid,
358
+                type: "POST",
359
+                data: { userid: userid },
360
+                cache: false,
361
+                processData: false,
362
+                contentType: false,
363
+                success: function(currentbalanceflow) {
364
+
365
+                     $('#currentbalance').empty();
366
+                     $('#currentbalance').text(currentbalanceflow);
367
+                     $('#currentbalance').removeClass('icon-loading');
368
+                }
369
+            });
370
+          }
371
+
372
+          getflowbalance();
373
+
374
+       } else if (provider == "") {
375
+                $('#currentbalance').text("");
376
+                $('#currentbalance').removeClass('icon-loading');
377
+       }
378
+  });
379
+
380
+
381
+  // Refresh the list of Sender IDs
382
+  $("#refreshSenderIDs").on("click", function(event) {
383
+
384
+     $('#refreshSenderIDs').addClass('icon-loading');
385
+
386
+     var getsmsnumbersUrl = OC.generateUrl("/apps/sms_relentless/user/refreshavailablenumbers");
387
+     var selectednmbr = null;
388
+
389
+     $.ajax({
390
+          url: getsmsnumbersUrl + '/' + userid,
391
+          type: "POST",
392
+          data: { userid: userid },
393
+          cache: false,
394
+          processData: false,
395
+          contentType: false,
396
+          success: function(smsnmbrs) {
397
+
398
+                    $('#currentsmsnmbrs').empty();
399
+                    $('#currentsmsnmbrs').append("<option value='' selected='selected' disabled class='optselectsmsnb'>Choose an ID</option>");
400
+
401
+                    $.each(smsnmbrs, function(key, indsmsnmb) {
402
+                           $('#currentsmsnmbrs').append("<option value='"+ indsmsnmb +"' class='optselectsmsnb'>"+ indsmsnmb +"</option>");
403
+                    });
404
+
405
+                    $('#refreshSenderIDs').removeClass('icon-loading');
406
+          }
407
+     });
408
+  });
409
+
410
+
411
+  // If a Sender ID is selected
412
+  $("#currentsmsnmbrs").on("change", function () {
413
+
414
+          if ($("#currentsmsnmbrs option[value='']").length > 0) {
415
+
416
+              selectedid = $('#currentsmsnmbrs :selected').val();
417
+              var setIdsplit = selectedid.split(":");
418
+	      chosenProvider = setIdsplit[0];
419
+
420
+              // Set the valid MMS file extensions, maximum MMS message size, maximum message size when non-jpeg/png/gif files are included, maximum number of files and the info note content, for the chosen provider
421
+	      if (chosenProvider == "Tx") {
422
+		  validExtensions = ["jpg", "jpeg", "png", "gif", "mp3", "ogg", "amr", "mp4", "3gpp", "pdf", "vcf", "vcard", "txt"];
423
+		  // Maximum size of message text + files in KB
424
+		  maximumsize = 1024;
425
+                  maximumsizeinit = 1024;
426
+		  maxsizenonimage = 600;
427
+		  maximumfilenumber = 10;
428
+                  chosenProvFullName = "Telnyx";
429
+                  infonotecontent = "To send an MMS, you can upload media files or pick them from Nextcloud. You can add up to 10 files. For Telnyx, if you send only jpeg/jpg, png \
430
+                                     or gif files, the size of all the files plus the size of the text should be \
431
+                                     <a href='https://support.telnyx.com/en/articles/4450150-faqs-about-mms-at-telnyx' style='color:#1b60ba' target='_blank' \
432
+                                     rel='noreferrer noopener'>1024 KB</a> or less. If you send files of other formats, the total size of the files plus the size of the text should \
433
+                                     be 600 KB or less. Allowed formats are jpeg/jpg, png, gif, mp3, ogg, amr, mp4, 3gpp, pdf, vcf, vcard and txt. By default, Telnyx accounts are \
434
+                                     limited to <a href='https://support.telnyx.com/en/articles/3102823-mms-sending-and-receiving' style='color:#1b60ba' target='_blank' \
435
+                                     rel='noreferrer noopener'>1 MMS message per second</a>. Deliverability of MMS messages depends on the carrier and device of the receiver. \
436
+                                     Carriers can reject MMS messages with files exceeding a certain size. The best deliverability is achieved when sending jpeg/jpg, png or \
437
+                                     gif files, with a total message size of 600 KB or less. Telnyx allows sending MMS messages only from US or Canadian phone numbers to other US \
438
+                                     or Canadian phone numbers. Although all the specified file types can be added to the MMS, only the most common media file types (jpeg/jpg, png, \
439
+                                     gif, mp4, ogg, etc.) can be previewed in the adjoining pane.";
440
+                  $("#tooltiptextfourth").html(infonotecontent);
441
+	      } else if (chosenProvider == "Pl") {
442
+		  validExtensions = ["jpg", "jpeg", "png", "gif", "bmp", "wav", "wave", "mp4", "amr", "mpg", "mpeg", "3gpp", "3gpp2", "vcf", "vcard", "x-vcard", "ics", "ical", "ifb", 
443
+                                     "icalendar", "csv", "txt", "pdf", "xls"];
444
+		  // Maximum size of message text + files in KB
445
+		  maximumsize = 5120;
446
+                  maximumsizeinit = 5120;
447
+		  maxsizenonimage = 600;
448
+		  maximumfilenumber = 10;
449
+                  chosenProvFullName = "Plivo";
450
+                  infonotecontent = "To send an MMS, you can upload media files or pick them from Nextcloud. You can add up to 10 files. For Plivo, if you send only jpeg/jpg, png \
451
+                                     or gif files, the size of all the files plus the size of the text should be \
452
+                                     <a href='https://support.plivo.com/hc/en-us/articles/360042280091-What-are-the-MMS-upload-size-limits-and-file-restrictions-' \
453
+                                     style='color:#1b60ba' target='_blank' rel='noreferrer noopener'>5120 KB</a> or less. If you send files of other formats, the total size \
454
+                                     of the files plus the size of the text should be 600 KB or less. <a href='https://support.plivo.com/hc/en-us/articles/360042273051' \
455
+                                     style='color:#1b60ba' target='_blank' rel='noreferrer noopener'>Allowed formats</a> are jpeg/jpg, png, gif, bmp, wav/wave, mp4, amr, mpg, mpeg, 3gpp, \
456
+                                     3gpp2, vcf, vcard, x-vcard, ics, ical, ifb, icalendar, csv, txt, pdf and xls. Deliverability of MMS messages depends on the carrier and \
457
+                                     device of the receiver. Carriers can reject MMS messages with files exceeding a certain size. The best deliverability is \
458
+                                     achieved when sending jpeg/jpg, png or gif files, with a total message size of 600 KB or less. Plivo allows sending MMS messages \
459
+                                     only from US or Canadian phone numbers to other US or Canadian phone numbers. Although all the specified file types can be added to the MMS, \
460
+                                     only the most common media file types (jpeg/jpg, png, gif, wav/wave, mp4, etc.) can be previewed in the adjoining pane.";
461
+                  $("#tooltiptextfourth").html(infonotecontent);
462
+	      } else if (chosenProvider == "Tw") {
463
+		  validExtensions = ["jpg", "jpeg", "png", "gif", "bmp", "tiff", "tif", "au", "snd", "l16", "wav", "wave", "aiff", "pcm", "mp4", "ogg", "ra", "ram", "3gpp", 
464
+                                     "3gpp2", "ac3", "webm", "amr", "mpg", "mpeg", "mov", "qt", "h261", "h263", "h264", "vcf", "vcard", "x-vcard", "csv", "rtf", "ics", "ical", "ifb", 
465
+                                     "icalendar", "directory", "pdf", "pkpass"];
466
+		  // Maximum size of message text + files in KB
467
+		  maximumsize = 5120;
468
+                  maximumsizeinit = 5120;
469
+		  maxsizenonimage = 600;
470
+		  maximumfilenumber = 10;
471
+                  chosenProvFullName = "Twilio";
472
+                  infonotecontent = "To send an MMS, you can upload media files or pick them from Nextcloud. You can add up to 10 files. For Twilio, if you send only jpeg/jpg, png \
473
+                                     or gif files, the size of all the files plus the size of the text should be \
474
+                                     <a href='https://support.twilio.com/hc/en-us/articles/360018832773-Twilio-Programmable-SMS-Supported-File-Types-and-Size-Limits-for-MMS-Media-Messages' \
475
+                                     style='color:#1b60ba' target='_blank' rel='noreferrer noopener'>5120 KB</a> or less. If you send files of other formats, the total size \
476
+                                     of the files plus the size of the text should be 600 KB or less. <a href='https://www.twilio.com/docs/sms/accepted-mime-types' \
477
+                                     style='color:#1b60ba' target='_blank' rel='noreferrer noopener'>Allowed formats</a> are jpeg/jpg, png, gif, bmp, tiff/tif, au, snd, l16, \
478
+                                     wav/wave, aiff, pcm, mp4, ogg, ra, ram, 3gpp, 3gpp2, ac3, webm, amr, mpg, mpeg, mov, qt, h261, h263, h264, vcf, vcard, x-vcard, csv, rtf, ics, \
479
+                                     ical, ifb, icalendar, directory, pdf and pkpass. Deliverability of MMS messages depends on the carrier and device of the receiver. Carriers \
480
+                                     can reject MMS messages with files exceeding a certain size. The best deliverability is achieved when sending jpeg/jpg, png or gif files, \
481
+                                     with a total message size of 600 KB or less. Twilio allows sending MMS messages from US or Canadian phone numbers to other US or Canadian phone \
482
+                                     numbers. However, MMS messages sent internationally will be converted to SMS messages with URL links to the included files. Although all the \
483
+                                     specified file types can be added to the MMS, only the most common media file types (jpeg/jpg, png, gif, wav/wave, mp4, ogg, etc.) can be \
484
+                                     previewed in the adjoining pane."
485
+                  $("#tooltiptextfourth").html(infonotecontent);
486
+	      } else if (chosenProvider == "Fl") {
487
+		  validExtensions = ["jpg", "jpeg", "png", "gif", "bmp", "3gp", "mp4", "avi", "amr", "midi", "wav", "wave", "ac3", "mp3"];
488
+		  // Maximum size of message text + files in KB
489
+		  maximumsize = 750;
490
+                  maximumsizeinit = 750;
491
+		  maxsizenonimage = 600;
492
+		  maximumfilenumber = 10;
493
+                  chosenProvFullName = "Flowroute";
494
+                  infonotecontent = "To send an MMS, you can upload media files or pick them from Nextcloud. You can add up to 10 files. For Flowroute, if you send only jpeg/jpg, \
495
+                                     png or gif files, the size of all the files plus the size of the text should be \
496
+                                     <a href='https://developer.flowroute.com/api/messages/v2.1/send-an-mms/' style='color:#1b60ba' target='_blank' \
497
+                                     rel='noreferrer noopener'>750 KB</a> or less. If you send files of other formats, the total \
498
+                                     size of the files plus the size of the text should be 600 KB or less. \
499
+                                     <a href='https://support.flowroute.com/937402-What-file-types-does-Flowroute-MMS-support' style='color:#1b60ba' target='_blank' \
500
+                                     rel='noreferrer noopener'>Allowed formats</a> are jpeg/jpg, png, gif, bmp, 3gp, mp4, avi, amr, midi, wav/wave, ac3 and mp3. Flowroute accounts are \
501
+                                     limited to <a href='https://developer.flowroute.com/docs/sms-mms-best-practices/#sending-and-receiving-limitations' style='color:#1b60ba' \
502
+                                     target='_blank' rel='noreferrer noopener'>1 MMS message per second</a>. Deliverability of MMS messages depends on the carrier and device \
503
+                                     of the receiver. Carriers can reject MMS messages with files exceeding a certain size. The best deliverability is achieved when sending \
504
+                                     jpeg/jpg, png or gif files, with a total message size of 600 KB or less. Flowroute allows sending MMS messages only from US or Canadian phone \
505
+                                     numbers to other US or Canadian phone numbers. Although all the specified file types can be added to the MMS, only the most common media file \
506
+                                     types (jpeg/jpg, png, gif, wav/wave, mp4, etc.) can be previewed in the adjoining pane."
507
+                  $("#tooltiptextfourth").html(infonotecontent);
508
+	      }
509
+
510
+          } else { selectedid = ''; }
511
+  });
512
+
513
+  // Check the checkbox to send SMS message to multiple recipients
514
+  $('#tomultchckbx').change(function() {
515
+      if ($(this).is(':checked')) {
516
+          $("#multiplerecivers").css("display", "block");
517
+          $("#smstodiv").css("visibility", "hidden");
518
+          $("#smsto").val("");
519
+
520
+          receiversNumbers.length = 0;
521
+
522
+      } else {
523
+          $("#multiplerecivers").css("display", "none");
524
+          $("#smstodiv").css("visibility", "visible");
525
+
526
+          // Remove the uploaded files' names if any
527
+          $("#induploadfile").remove();
528
+
529
+          // Remove all the files from the SMS_Relentless/multiple_recipients directory
530
+          cleanMultRecDirectory();
531
+
532
+          $("#smstables").empty();
533
+          $("#stopAutoRefreshRec,#stopAutoRefreshSent").css("display", "none");
534
+
535
+          receiversNumbers.length = 0;
536
+      }
537
+  });
538
+
539
+  // Upload the file with the recipients' phone numbers
540
+  $("#uploadfileforsms").change(function(e) {
541
+
542
+     $("#fileuploadednm").empty();
543
+
544
+     receiversNumbers.length = 0;
545
+
546
+     OC.msg.startAction("#sms_upload_msg", t("sms_relentless", "Uploading ..."));
547
+
548
+     var baseUrl = OC.generateUrl("/apps/sms_relentless/user/upload_numbers_file");
549
+
550
+     var formData = new FormData();
551
+     formData.append('uploadfileforsms', $('#uploadfileforsms')[0].files[0]);
552
+
553
+     var fileup = $('#uploadfileforsms').val();
554
+     var fileuptrim = fileup.split('\\').pop();
555
+
556
+     $('#fileuploadednm').append("<div id='induploadfile' class='indgenflcls'><div id='indfilediv' class='indivflcls'>" + fileuptrim + "</div><div id='indivflremove' class='indupfldl'>X</div></div><br>");
557
+
558
+     var extension = fileup.replace(/^.*\./, '');
559
+
560
+     if (extension == fileup) {
561
+         extension = "";
562
+     } else {
563
+         extension = extension.toLowerCase();
564
+     }
565
+
566
+     var validExtensionsmrec = ["txt", "csv"];
567
+
568
+     if (jQuery.inArray(extension, validExtensionsmrec) != -1) {
569
+
570
+       if (selectedid != '') {
571
+
572
+               $.ajax({
573
+                 url: baseUrl + '/' + userid,
574
+                 type: "POST",
575
+                 data: formData,
576
+                 cache: false,
577
+                 processData: false,
578
+                 contentType: false,
579
+                 success: function(numberarray) {
580
+
581
+		    if (numberarray.length > 0) {
582
+
583
+		        // Get the array of the receivers' phone numbers
584
+		        if (chosenProvider == "Tx") {
585
+
586
+		             for(key in numberarray) {
587
+		                 receiversNumbers.push("+"+numberarray[key]);
588
+		             }
589
+
590
+		        } else if (chosenProvider == "Pl") {
591
+
592
+		             for(key in numberarray) {
593
+		                 receiversNumbers.push(numberarray[key]);
594
+		             }
595
+
596
+		          } else if (chosenProvider == "Tw") {
597
+
598
+		             for(key in numberarray) {
599
+		                 receiversNumbers.push(numberarray[key]);
600
+		             }
601
+		          } else if (chosenProvider == "Fl") {
602
+
603
+		             for(key in numberarray) {
604
+		                 receiversNumbers.push(numberarray[key]);
605
+		             }
606
+		          }
607
+
608
+		    } else {
609
+                          showAlert("The uploaded file doesn't seem to contain any valid phone numbers. Please upload a txt or csv file that contains phone numbers separated by commas, semicolons, vertical bars or new lines.");
610
+		    }
611
+                            
612
+                    // Preview the uploaded file
613
+                    var smsfilename = e.target.files[0].name;
614
+                    var baseUrl = OC.generateUrl("/remote.php/webdav/SMS_Relentless/temp_files/"+smsfilename);
615
+
616
+                    var reader = new FileReader();
617
+                    reader.readAsText(e.target.files[0]);
618
+                    reader.onload = function(e) {
619
+                          $("#smstables").empty();
620
+                          $("#stopAutoRefreshRec,#stopAutoRefreshSent").css("display", "none");
621
+                          $("#smstables").append(e.target.result.replace(/(?:\r\n|\r|\n)/g, '<br>'));
622
+                    };
623
+
624
+                    $("#smstables").show();
625
+
626
+                    $('#sms_upload_msg').hide();
627
+                    $('#smstables').removeClass('icon-loading');
628
+
629
+                  },
630
+                  error: function() {
631
+                             showAlert("Error while uploading the file.");
632
+                  }
633
+               });
634
+
635
+        } else {
636
+               showAlert("Please choose a Sender ID from the Set ID drop-down list!");
637
+               $("#induploadfile").remove();
638
+               $('#sms_upload_msg').hide();
639
+               $('#smstables').removeClass('icon-loading');
640
+        }
641
+
642
+     } else {
643
+          showAlert("The file type is not supported ! Supported formats are txt and csv.");
644
+          $('#pf_upload_msg').hide();
645
+          $('#smstables').removeClass('icon-loading');
646
+
647
+          $("#induploadfile").remove();
648
+          $("#sms_upload_msg").hide();
649
+     }
650
+
651
+     // Preview uploaded file when clicked
652
+     $("#indfilediv").on("click", function() {
653
+
654
+          var smsfilename = e.target.files[0].name;
655
+          var baseUrl = OC.generateUrl("/remote.php/webdav/SMS_Relentless/temp_files/"+smsfilename);
656
+
657
+          var reader = new FileReader();
658
+          reader.readAsText(e.target.files[0]);
659
+          reader.onload = function(e) {
660
+                  $("#smstables").empty();
661
+                  $("#stopAutoRefreshRec,#stopAutoRefreshSent").css("display", "none");
662
+                  $("#smstables").append(e.target.result.replace(/(?:\r\n|\r|\n)/g, '<br>'));
663
+          };
664
+
665
+          $("#smstables").show();
666
+          $('#sms_upload_msg').hide();
667
+          $('#smstables').removeClass('icon-loading');
668
+     });
669
+
670
+     // Remove selected file
671
+     $("#indivflremove").on("click", function() {
672
+
673
+          $("#induploadfile").remove();
674
+          $("#sms_upload_msg").hide();
675
+
676
+          receiversNumbers.length = 0;
677
+
678
+          cleanMultRecDirectory();
679
+     });
680
+
681
+  });
682
+
683
+  // Show the number of characters entered in the SMS textarea and the text size in KB
684
+  $("#smstext").on('input', function() {
685
+
686
+     $("#char_count").css("display", "inline");
687
+
688
+     $("#mtextSize").css("display", "inline");
689
+
690
+     $(".maxmessagelength").css("display", "inline-block");
691
+
692
+     $("#countchnb").text($(this).val().length);
693
+
694
+     var textsize = encodeURIComponent($(this).val()).replace(/%[A-F\d]{2}/g, 'U').length;
695
+     textsizekb = parseFloat(textsize/1024).toFixed(4);
696
+     $("#textsizeinkb").text(textsizekb);
697
+
698
+     if ($(this).val().length > charcolorthr) {
699
+         $("#char_count").css("color", "#BB2E4B");
700
+     } else {
701
+         $("#char_count").css("color", "#4cbc86;");
702
+     }
703
+
704
+  });
705
+
706
+
707
+  // Check the checkbox to send file(s) as MMS
708
+  $('#mediafilechckbx').change(function() {
709
+
710
+      if ($(this).is(':checked')) {
711
+
712
+          isMMS = 1;
713
+          if (selectedid == '') {
714
+              showAlert("Please, first choose a Sender ID from the Set ID drop-down list !");
715
+              $(this).prop("checked", false);
716
+              isMMS = 0;
717
+              return;
718
+          }
719
+          $("#upmediafiles").css("display", "block");
720
+          $("#submitsms").prop("value", "Send MMS");
721
+          $("#smstext").prop("placeholder", "Enter a message here, then press 'Send MMS'.");
722
+
723
+      } else {
724
+
725
+          isMMS = 0;
726
+          $("#upmediafiles").css("display", "none");
727
+          $("#submitsms").prop("value", "Send SMS");
728
+          $("#smstext").prop("placeholder", "Enter a message here, then press 'Send SMS'.");
729
+
730
+          // Remove the uploaded files' names if any
731
+          $(".indgenflclsmms").each(function() { $(this).remove(); });
732
+          $(".indgenpckfls").each(function() { $(this).remove(); });
733
+
734
+          // Remove all the files from the SMS_Relentless/temp_files directory
735
+          cleanTempDirectory();
736
+
737
+          $("#smstables").empty();
738
+          $("#stopAutoRefreshRec,#stopAutoRefreshSent").css("display", "none");
739
+
740
+          uploadedtomms = [];
741
+          n = 1;
742
+
743
+          msgtotalflsize = 0;
744
+
745
+          $("#filestotsize").hide();
746
+      }
747
+  });
748
+
749
+
750
+  // Check if the uploaded files' format is jpeg, png or gif and adjust the maximum cumulative size of files, if necessary
751
+  function adjustMaximumSize(uploadedtomms) {
752
+				      
753
+      var nonimgcheck = 0;
754
+      for (var u = 0; u < uploadedtomms.length; u++) {
755
+	   var crupfl = uploadedtomms[u];
756
+	   var extensionup = crupfl.replace(/^.*\./, '');
757
+	   if ($.inArray(extensionup, ["jpg", "jpeg", "png", "gif"]) === -1) {
758
+	       nonimgcheck = 1;
759
+	   }
760
+      }
761
+
762
+      if (nonimgcheck == 0) { maximumsize = maximumsizeinit; }
763
+  }
764
+
765
+  // Upload files to be sent as MMS
766
+  $("#uploadfileformms").change(function(e) {
767
+
768
+     OC.msg.startAction("#pf_upload_msg", t("sms_relentless", "Uploading ..."));
769
+     $('#smstables').addClass('icon-loading');
770
+     $('#filestotsize').show();
771
+
772
+     var userid = "<?php p($userId); ?>";
773
+     var baseUrl = OC.generateUrl("/apps/sms_relentless/user/uploadfile");
774
+
775
+     var formData = new FormData();
776
+     formData.append('uploadfileformms', $('#uploadfileformms')[0].files[0]);
777
+
778
+     var currentflsize = $('#uploadfileformms')[0].files[0].size;
779
+
780
+     // Add the size of the current file to the total size of all the files
781
+     msgtotalflsize += Math.floor((currentflsize/1024) * 100)/100;
782
+
783
+     var fileup = $('#uploadfileformms').val();
784
+     var fileuptrim = fileup.split('\\').pop();
785
+
786
+     if ($.inArray(fileuptrim, uploadedtomms) != -1) {
787
+         var duplicatescheck = 1;
788
+     } else { 
789
+         var duplicatescheck = 0;
790
+     }
791
+
792
+     var extension = fileup.replace(/^.*\./, '');
793
+
794
+     if (extension == fileup) {
795
+         extension = "";
796
+     } else {
797
+         extension = extension.toLowerCase();
798
+     }
799
+
800
+     // If the uploaded file's format is different from jpeg, png or gif, the maximum allowed size of the message will be lower
801
+     if (($.inArray(extension, ["jpg", "jpeg", "png", "gif"]) === -1) && (msgtotalflsize <= Number(maximumsize) - Number(textsizekb))) {
802
+         maximumsize = maxsizenonimage;
803
+     }
804
+
805
+     if ($.inArray(extension, validExtensions) != -1) {
806
+
807
+       if (duplicatescheck == 0) {
808
+
809
+         if (msgtotalflsize <= Number(maximumsize) - Number(textsizekb)) {
810
+
811
+            if (n <= maximumfilenumber) {
812
+
813
+               $.ajax({
814
+                 url: baseUrl + '/' + userid,
815
+                 type: "POST",
816
+                 data: formData,
817
+                 cache: false,
818
+                 processData: false,
819
+                 contentType: false,
820
+                 success: function(totalflsize) {
821
+
822
+                   uploadedtomms.push(fileuptrim);
823
+
824
+                   $('#filessizetext').text(totalflsize);
825
+
826
+                   var rectotfilesz = parseFloat(totalflsize);
827
+
828
+                   if (rectotfilesz <= maximumsize) {
829
+                       $('#submitsms').attr("disabled", false);
830
+                       $('#filestotsize').css('color', '#189558');
831
+                   } else {
832
+                       $('#filestotsize').css('color', '#ba3555');
833
+                       showAlert("Error ! For "+ chosenProvFullName +", for the chosen files format, the size of all the included files plus the size of the text cannot exceed "+ maximumsize +" KB !");
834
+                       $('#submitsms').attr("disabled", true);
835
+                       $('#smstables').removeClass('icon-loading');
836
+                       $('#pf_upload_msg').hide();
837
+                   }
838
+
839
+                   $('#mmsfileuploadednm').append("<div class='indgenflclsmms'><div id='"+n+"indfilediv' class='indivflcls'>" + n + ") " + fileuptrim + "</div><div class='indupfldl'>X</div></div>");
840
+                   n++;
841
+
842
+                   // Preview the file when you click on its name
843
+                   $("div:visible[id*='indfilediv']").each(function() {
844
+
845
+                        $(this).on("click", function(eventclck) {
846
+
847
+                           $("#mmsfoldersview").css("display", "inline-block");
848
+                           var mmsfilenameinit = $(this).text();
849
+                           var mmsfilenamesec = mmsfilenameinit.substring(mmsfilenameinit.indexOf(" ") + 1);
850
+                           var mmsfilename = mmsfilenamesec.replace("X","");
851
+                           var baseUrl = firstPathEl+"/remote.php/webdav/SMS_Relentless/temp_files/"+mmsfilename;
852
+                           var extenlst = mmsfilename.replace(/^.*\./, '');
853
+
854
+                           if (extenlst == mmsfilename) {
855
+                               extenlst = "";
856
+                           } else {
857
+                               extenlst = extenlst.toLowerCase();
858
+                           }
859
+
860
+                           $("#smstables").empty();
861
+                           $("#stopAutoRefreshRec,#stopAutoRefreshSent").css("display", "none");
862
+
863
+                           if (extenlst == 'jpg' || extenlst == 'jpeg') {
864
+                                  $("#smstables").append('<img style="width:auto;height:auto" id="uploadedjpg" src="#" />');
865
+                                  $("#uploadedjpg").attr('src', readjpg[mmsfilename]);
866
+                           } else if (extenlst == 'png') {
867
+                                  $("#smstables").append('<img style="width:auto;height:auto" id="uploadedpng" src="#" />');
868
+                                  $("#uploadedpng").attr('src', readpng[mmsfilename]);
869
+                           } else if (extenlst == 'gif') {
870
+                                  $("#smstables").append('<img style="width:auto;height:auto" id="uploadedgif" src="#" />');
871
+                                  $("#uploadedgif").attr('src', readgif[mmsfilename]);
872
+                           } else if (extenlst == 'bmp') {
873
+                                  $("#smstables").append('<img style="width:auto;height:auto" id="uploadedbmp" src="#" />');
874
+                                  $("#uploadedbmp").attr('src', readbmp[mmsfilename]);
875
+                           } else if (extenlst == 'tif' || extenlst == 'tiff') {
876
+                                  var tiffile = '/remote.php/webdav/SMS_Relentless/temp_files/'+mmsfilename;
877
+                                  var xhr = new XMLHttpRequest();
878
+                                  xhr.responseType = 'arraybuffer';
879
+                                  xhr.open('GET', tiffile);
880
+                                  xhr.onload = function (evnt) {
881
+                                      var tiff = new Tiff({buffer: xhr.response});
882
+                                      var tifcanvas = tiff.toCanvas();
883
+                                      $("#smstables").append(tifcanvas);
884
+                                  };
885
+                                  xhr.send();
886
+                           } else if (extenlst == 'pdf') {
887
+                                  var viewerclick = OC.generateUrl('/apps/files_pdfviewer/?file={file}', {file: baseUrl});
888
+                                  var $iframe = $('<iframe id="docclickview" style="width:100%;height:100%;display:block;position:absolute;top:0;left:0;z-index:1041;" src="' + viewerclick + '" sandbox="allow-scripts allow-same-origin allow-popups allow-modals"></iframe>');
889
+                                  $("#smstables").append($iframe);
890
+                           } else if (extenlst == 'txt') {
891
+                                  $("#smstables").append(readtxtfile[mmsfilename]);
892
+                           } else if (extension == 'mp4') {
893
+                                  $("#smstables").append('<video width="100%" height="auto" controls><source id="uploadedmp4" src="'+ baseUrl +'"></video>');
894
+		           } else if (extension == 'ogg') {
895
+		                  $("#smstables").append('<video width="100%" height="auto" controls><source id="uploadedogg" src="'+ baseUrl +'"></video>');
896
+		           } else if (extension == 'avi') {
897
+		                  $("#smstables").append('<video width="100%" height="auto" controls><source id="uploadedavi" src="'+ baseUrl +'" type="video/avi"></video>');
898
+		           } else if (extension == 'mpg' || extension == 'mpeg') {
899
+		                  $("#smstables").append('<video width="100%" height="auto" controls><source id="uploadedmpg" src="'+ baseUrl +'"></video>');
900
+		           } else if (extension == 'wav' || extension == 'wave') {
901
+		                  $("#smstables").append('<audio width="100%" height="auto" controls><source id="uploadedwav" src="'+ baseUrl +'"></audio>');
902
+		           } else if (extension == 'mp3') {
903
+		                  $("#smstables").append('<audio width="100%" height="auto" controls><source id="uploadedmp3" src="'+ baseUrl +'" type="audio/mp3"></audio>');
904
+		           } else if (extension == 'midi') {
905
+		                  $("#smstables").append('<audio width="100%" height="auto" controls><source id="uploadedmidi" src="'+ baseUrl +'" type="audio/midi"></audio>');
906
+		           }
907
+
908
+                           $("#smstables").show();
909
+                           $("#mmsfoldersview").hide();
910
+                        });
911
+                   });
912
+
913
+                   // Remove uploaded files
914
+                   $('[class*="indupfldl"]').last().click(function() {
915
+
916
+                           var userid = "<?php p($userId); ?>";
917
+                           var baseUrl = OC.generateUrl("/apps/sms_relentless/user/removeupfile");
918
+
919
+                           var removedfilenameinit = $(this).closest('[class*="indgenflclsmms"]').find('[class*="indivflcls"]').text();
920
+
921
+                           var removedfilesplit = removedfilenameinit.split(") ");
922
+                           var removedflnb = parseInt(removedfilesplit[0]);
923
+
924
+                           $(this).closest('[class*="indgenflclsmms"]').find('[class*="indivflcls"]').hide();
925
+                           $(this).hide();
926
+
927
+                           var removedfilename = removedfilenameinit.substring(removedfilenameinit.indexOf(" ") + 1);
928
+
929
+                           uploadedtomms = $.grep(uploadedtomms, function(value) {
930
+                                           return value != removedfilename;
931
+                           });
932
+
933
+                           $.ajax({
934
+                                   url: baseUrl + '/' + userid,
935
+                                   type: "POST",
936
+                                   data: {removedfilename: removedfilename},
937
+                                   success: function(totalflsize) {
938
+
939
+                                      msgtotalflsize = totalflsize;
940
+                                      $('#filessizetext').text(totalflsize);
941
+
942
+                                      adjustMaximumSize(uploadedtomms);
943
+
944
+                                      // Check message size
945
+                                      var rectotfilesz = parseFloat(totalflsize);
946
+
947
+                                      if (rectotfilesz <= Number(maximumsize) - Number(textsizekb)) {
948
+                                          $('#submitsms').attr("disabled", false);
949
+                                          $('#filestotsize').css('color', '#189558');
950
+                                      } else {
951
+                                          $('#filestotsize').css('color', '#ba3555');
952
+                                          showAlert("Error ! For "+ chosenProvFullName +", for the chosen files format, the total size of the included files plus the size of the text cannot exceed "+ maximumsize +" KB !");
953
+                                          $('#submitsms').attr("disabled", true);
954
+                                      }
955
+
956
+                                      // Rewrite order numbers for files that follow
957
+                                      --n;
958
+                                      $("div:visible[id*='indfilediv']").each(function() {
959
+
960
+                                          var getdivtext =  $(this).text();
961
+                                          var splitdivtext = getdivtext.split(") ");
962
+                                          var currentnbvalue = parseInt(splitdivtext[0]);
963
+                                          var newnbvalue = currentnbvalue - 1;
964
+
965
+                                          if (currentnbvalue > removedflnb) {
966
+                                              var replacedstr = newnbvalue + ") " + splitdivtext[1];
967
+                                              $(this).text(replacedstr);
968
+                                          }
969
+                                      });
970
+
971
+                                      $("div:visible[id*='indflpicked']").each(function() {
972
+
973
+                                          var getdivtext =  $(this).text();
974
+                                          var splitdivtext = getdivtext.split(") ");
975
+                                          var currentnbvalue = parseInt(splitdivtext[0]);
976
+                                          var newnbvalue = currentnbvalue - 1;
977
+
978
+                                          if (currentnbvalue > removedflnb) {
979
+                                              var replacedstr = newnbvalue + ") " + splitdivtext[1];
980
+                                              $(this).text(replacedstr);
981
+                                          }
982
+                                      });
983
+
984
+                                   },
985
+                                   error: function() {
986
+                                              showAlert("Error while removing the file(s).");
987
+                                   }
988
+                           });
989
+
990
+                           $('#smstables').removeClass('icon-loading');
991
+                           $("#smstables").empty();
992
+                   });
993
+
994
+                   // Preview the uploaded file
995
+                   $("#mmsfoldersview").css("display", "inline-block");
996
+                   var mmsfilename = e.target.files[0].name;
997
+                   var baseUrl = firstPathEl+"/remote.php/webdav/SMS_Relentless/temp_files/"+mmsfilename;
998
+
999
+                   $("#smstables").empty();
1000
+                   $("#stopAutoRefreshRec,#stopAutoRefreshSent").css("display", "none");
1001
+
1002
+                   if (extension == 'jpg' || extension == 'jpeg') {
1003
+                              $("#smstables").append('<img style="width:auto;height:auto" id="uploadedjpg" src="#" />');
1004
+
1005
+                              var reader = new FileReader();
1006
+                              reader.onload = function (e) {
1007
+                                  readjpg[mmsfilename] = e.target.result;
1008
+                                  $("#uploadedjpg").attr('src', readjpg[mmsfilename]);
1009
+                              }
1010
+                              reader.readAsDataURL(e.target.files[0]);
1011
+                   } else if (extension == 'png') {
1012
+                              $("#smstables").append('<img style="width:auto;height:auto" id="uploadedpng" src="#" />');
1013
+
1014
+                              var reader = new FileReader();
1015
+                              reader.onload = function (e) {
1016
+                                  readpng[mmsfilename] = e.target.result;
1017
+                                  $("#uploadedpng").attr('src', readpng[mmsfilename]);
1018
+                              }
1019
+                              reader.readAsDataURL(e.target.files[0]);
1020
+
1021
+                   } else if (extension == 'gif') {
1022
+                              $("#smstables").append('<img style="width:auto;height:auto" id="uploadedgif" src="#" />');
1023
+
1024
+                              var reader = new FileReader();
1025
+                              reader.onload = function (e) {
1026
+                                  readgif[mmsfilename] = e.target.result;
1027
+                                  $("#uploadedgif").attr('src', readgif[mmsfilename]);
1028
+                              }
1029
+                              reader.readAsDataURL(e.target.files[0]);
1030
+
1031
+                   } else if (extension == 'bmp') {
1032
+                              $("#smstables").append('<img style="width:auto;height:auto" id="uploadedbmp" src="#" />');
1033
+
1034
+                              var reader = new FileReader();
1035
+                              reader.onload = function (e) {
1036
+                                  readbmp[mmsfilename] = e.target.result;
1037
+                                  $("#uploadedbmp").attr('src', readbmp[mmsfilename]);
1038
+                              }
1039
+                              reader.readAsDataURL(e.target.files[0]);
1040
+
1041
+                   } else if (extension == 'tif' || extension == 'tiff') {
1042
+                              var tiffile = '/remote.php/webdav/SMS_Relentless/temp_files/'+mmsfilename;
1043
+                              var xhr = new XMLHttpRequest();
1044
+                              xhr.responseType = 'arraybuffer';
1045
+                              xhr.open('GET', tiffile);
1046
+                              xhr.onload = function (e) {
1047
+                                  var tiff = new Tiff({buffer: xhr.response});
1048
+                                  var tifcanvas = tiff.toCanvas();
1049
+                                  $("#smstables").append(tifcanvas);
1050
+                              };
1051
+                              xhr.send();
1052
+
1053
+                   } else if (extension == 'pdf') {
1054
+                              var viewer = OC.generateUrl('/apps/files_pdfviewer/?file={file}', {file: baseUrl});
1055
+                              var $iframe = $('<iframe id="docviewer" style="width:100%;height:100%;display:block;position:absolute;top:0;left:0;z-index:1041;" src="' + viewer + '" sandbox="allow-scripts allow-same-origin allow-popups allow-modals"></iframe>');
1056
+                              $("#smstables").append($iframe);
1057
+
1058
+                   } else if (extension == 'txt') {
1059
+                              var reader = new FileReader();
1060
+                              reader.readAsText(e.target.files[0]);
1061
+                              reader.onload = function(e) {
1062
+                                  readtxtfile[mmsfilename] = e.target.result.replace(/(?:\r\n|\r|\n)/g, '<br>');
1063
+                                  $("#smstables").append(readtxtfile[mmsfilename]);
1064
+                              };
1065
+                   } else if (extension == 'mp4') {
1066
+                              $("#smstables").append('<video width="100%" height="auto" controls><source id="uploadedmp4" src="'+ baseUrl +'"></video>');
1067
+                   } else if (extension == 'ogg') {
1068
+                              $("#smstables").append('<video width="100%" height="auto" controls><source id="uploadedogg" src="'+ baseUrl +'"></video>');
1069
+                   } else if (extension == 'avi') {
1070
+                              $("#smstables").append('<video width="100%" height="auto" controls><source id="uploadedavi" src="'+ baseUrl +'" type="video/avi"></video>');
1071
+                   } else if (extension == 'mpg' || extension == 'mpeg') {
1072
+                              $("#smstables").append('<video width="100%" height="auto" controls><source id="uploadedmpg" src="'+ baseUrl +'"></video>');
1073
+                   } else if (extension == 'wav' || extension == 'wave') {
1074
+                              $("#smstables").append('<audio width="100%" height="auto" controls><source id="uploadedwav" src="'+ baseUrl +'"></audio>');
1075
+                   } else if (extension == 'mp3') {
1076
+                              $("#smstables").append('<audio width="100%" height="auto" controls><source id="uploadedmp3" src="'+ baseUrl +'" type="audio/mp3"></audio>');
1077
+                   } else if (extension == 'midi') {
1078
+                              $("#smstables").append('<audio width="100%" height="auto" controls><source id="uploadedmidi" src="'+ baseUrl +'" type="audio/midi"></audio>');
1079
+                   }
1080
+
1081
+                   $("#smstables").show();
1082
+                   $('#pf_upload_msg').hide();
1083
+                   $('#smstables').removeClass('icon-loading');
1084
+                   $("#mmsfoldersview").hide();
1085
+                 },
1086
+                 error: function() {
1087
+                              showAlert("Error while uploading the file.");
1088
+                 }
1089
+               });
1090
+
1091
+            } else {
1092
+                  msgtotalflsize -= Math.floor((currentflsize/1024) * 100)/100;
1093
+                  adjustMaximumSize(uploadedtomms);
1094
+
1095
+                  showAlert("Error! You cannot send more than 10 files in one MMS !");
1096
+                  $('#pf_upload_msg').hide();
1097
+                  $('#smstables').removeClass('icon-loading');
1098
+            }
1099
+         } else {
1100
+              msgtotalflsize -= Math.floor((currentflsize/1024) * 100)/100;
1101
+              adjustMaximumSize(uploadedtomms);
1102
+
1103
+              showAlert("Error ! For "+ chosenProvFullName +", for the chosen files format, the size of all the included files plus the size of the text cannot be greater than "+ maxsizenonimage +" KB !");
1104
+              $('#pf_upload_msg').hide();
1105
+              $('#smstables').removeClass('icon-loading');
1106
+         }
1107
+       } else {
1108
+            msgtotalflsize -= Math.floor((currentflsize/1024) * 100)/100;
1109
+            adjustMaximumSize(uploadedtomms);
1110
+
1111
+            showAlert("Error ! There is already a file named '"+ fileuptrim +"' in the 'SMS_Relentless/temp_files' folder !");
1112
+            $('#pf_upload_msg').hide();
1113
+            $('#smstables').removeClass('icon-loading');
1114
+       }
1115
+
1116
+     } else {
1117
+          msgtotalflsize -= Math.floor((currentflsize/1024) * 100)/100;
1118
+          adjustMaximumSize(uploadedtomms);
1119
+
1120
+          showAlert("The file type is not supported! Supported extensions for "+ chosenProvFullName +" are: "+ validExtensions.join(", ") +".");
1121
+          $('#pf_upload_msg').hide();
1122
+          $('#smstables').removeClass('icon-loading');
1123
+     }
1124
+  });
1125
+
1126
+
1127
+  // Pick file(s) from Nextcloud, to send as MMS
1128
+  var mmsfilename = null;
1129
+
1130
+  $("#choosefilen").on("click", function(evn) {
1131
+
1132
+                OC.dialogs.filepicker(
1133
+                        t('settings', "Select a file to send as MMS."),
1134
+                        function (path) {
1135
+
1136
+                              OC.msg.startAction("#pf_choose_msg", t("sms_relentless", "Please wait ..."));
1137
+                              $('#smstables').addClass('icon-loading');
1138
+                              $('#filestotsize').show();
1139
+
1140
+                              var userid = "<?php p($userId); ?>";
1141
+                              var baseUrl = OC.generateUrl("/apps/sms_relentless/user/pickfile");
1142
+
1143
+                              mmsfilename = path.split('/').pop();
1144
+
1145
+                              if ($.inArray(mmsfilename, uploadedtomms) != -1) {
1146
+                                  var duplicatescheck = 1;
1147
+                              } else var duplicatescheck = 0;
1148
+
1149
+                              var extension = mmsfilename.replace(/^.*\./, '');
1150
+
1151
+                              if (extension == mmsfilename) {
1152
+                                  extension = "";
1153
+                              } else {
1154
+                                  extension = extension.toLowerCase();
1155
+                              }
1156
+
1157
+			      // If the picked file's format is different from jpeg, png or gif, the maximum allowed size of the message will be lower
1158
+			      if ($.inArray(extension, ["jpg", "jpeg", "png", "gif"]) === -1) {
1159
+				   maximumsize = maxsizenonimage;
1160
+			      }
1161
+
1162
+                              if ($.inArray(extension, validExtensions) != -1) {
1163
+
1164
+                                 if (duplicatescheck == 0) {
1165
+
1166
+                                    if (n <= maximumfilenumber) {
1167
+
1168
+                                       $.ajax({
1169
+                                          url: baseUrl + '/' + userid,
1170
+                                          type: "POST",
1171
+                                          data: { path: path },
1172
+                                          success: function(pickresult) {
1173
+
1174
+                                                uploadedtomms.push(mmsfilename);
1175
+
1176
+                                                var totalflsize = pickresult[0];
1177
+                                                var pickedflsize = pickresult[1];
1178
+
1179
+                                                // Check message size
1180
+                                                var rectotfilesz = parseFloat(totalflsize);
1181
+                                                var filesplustextsize = Number(rectotfilesz) + Number(textsizekb);
1182
+
1183
+                                                if (filesplustextsize <= maximumsize) {
1184
+
1185
+                                                    $("#mmsfoldersview").css("display", "inline-block");
1186
+
1187
+                                                    $('#filespickednc').append("<div class='indgenpckfls'><div id='"+n+"indflpicked' class='indivflpckd'>" + n + ") " + mmsfilename + "</div><div class='indpckfldl'>X</div></div>");
1188
+                                                    n++;
1189
+
1190
+                                                    msgtotalflsize = totalflsize;
1191
+                                                    $('#filessizetext').text(totalflsize);
1192
+                                                    $('#filestotsize').css('color', '#189558');
1193
+
1194
+                                                } else {
1195
+
1196
+                                                    uploadedtomms = uploadedtomms.filter(function(e) { return e !== mmsfilename });
1197
+                                                    $('#filestotsize').css('color', '#ba3555');
1198
+                                                    msgtotalflsize -= pickedflsize;
1199
+                                                    var baseUrlindrm = OC.generateUrl("/apps/sms_relentless/user/removeupfile");
1200
+
1201
+                                                    $.ajax({
1202
+                                                        url: baseUrlindrm + '/' + userid,
1203
+                                                        type: "POST",
1204
+                                                        data: {removedfilename: mmsfilename},
1205
+                                                        success: function(totalflsize) {
1206
+
1207
+                                                                          $('#filessizetext').text(totalflsize);
1208
+                                                                          $('#filestotsize').css('color', '#189558');
1209
+                                                                          adjustMaximumSize(uploadedtomms);
1210
+
1211
+                                                        },
1212
+                                                        error: function(totalflsize) {
1213
+                                                                          $('#filessizetext').text(totalflsize);
1214
+                                                                          if (parseFloat(totalflsize) > maximumsize) {
1215
+                                                                              $('#filestotsize').css('color', '#ba3555');
1216
+                                                                          } else { $('#filestotsize').css('color', '#189558'); }
1217
+                                                                          showAlert("Error while trying to remove the last picked file from the 'SMS_Relentless/temp_files' directory!");
1218
+                                                        }
1219
+                                                    });
1220
+
1221
+                                                    showAlert("Error ! For "+ chosenProvFullName +", for the chosen files format, the size of all the included files plus the size of the text cannot exceed "+ maximumsize +" KB !");
1222
+                                                }
1223
+
1224
+
1225
+                                                // Preview each file when you click on its name
1226
+                                                $("div:visible[id*='indflpicked']").each(function() {
1227
+                                                   $(this).on("click", function(event) {
1228
+
1229
+                                                      var mmsfilenameinit = $(this).text();
1230
+                                                      var mmsfilenamesec = mmsfilenameinit.substring(mmsfilenameinit.indexOf(" ") + 1);
1231
+                                                      var mmsfilenamesp = mmsfilenamesec.replace("X","");
1232
+                                                      var baseUrl = firstPathEl+"/remote.php/webdav/SMS_Relentless/temp_files/"+mmsfilenamesp;
1233
+                                                      var extenlst = mmsfilenamesp.replace(/^.*\./, '');
1234
+
1235
+                                                      if (extenlst == mmsfilenamesp) {
1236
+                                                           extenlst = "";
1237
+                                                      } else {
1238
+                                                           extenlst = extenlst.toLowerCase();
1239
+                                                      }
1240
+
1241
+                                                      $("#smstables").empty();
1242
+                                                      $("#stopAutoRefreshRec,#stopAutoRefreshSent").css("display", "none");
1243
+
1244
+                                                      if (extenlst == 'jpg' || extenlst == 'jpeg') {
1245
+                                                              $("#smstables").append('<img style="width:auto;height:auto" id="uploadedjpg" src="'+ baseUrl +'" />');
1246
+                                                      } else if (extenlst == 'png') {
1247
+                                                              $("#smstables").append('<img style="width:auto;height:auto" id="uploadedpng" src="'+ baseUrl +'" />');
1248
+                                                      } else if (extenlst == 'gif') {
1249
+                                                              $("#smstables").append('<img style="width:auto;height:auto" id="uploadedgif" src="'+ baseUrl +'" />');
1250
+                                                      } else if (extenlst == 'bmp') {
1251
+                                                              $("#smstables").append('<img style="width:auto;height:auto" id="uploadedbmp" src="'+ baseUrl +'" />');
1252
+                                                      } else if (extenlst == 'tif' || extenlst == 'tiff') {
1253
+                                                              var tiffile = '/remote.php/webdav/SMS_Relentless/temp_files/'+mmsfilenamesp;
1254
+                                                              var xhr = new XMLHttpRequest();
1255
+                                                              xhr.responseType = 'arraybuffer';
1256
+                                                              xhr.open('GET', tiffile);
1257
+                                                              xhr.onload = function (evnt) {
1258
+                                                                  var tiff = new Tiff({buffer: xhr.response});
1259
+                                                                  var tifcanvas = tiff.toCanvas();
1260
+                                                                  $("#smstables").append(tifcanvas);
1261
+                                                              };
1262
+                                                              xhr.send();
1263
+                                                      } else if (extenlst == 'pdf') {
1264
+                                                              var viewerclick = OC.generateUrl('/apps/files_pdfviewer/?file={file}', {file: baseUrl});
1265
+                                                              var $iframe = $('<iframe id="docclickview" style="width:100%;height:100%;display:block;position:absolute;top:0;left:0;z-index:1041;" src="' + viewerclick + '" sandbox="allow-scripts allow-same-origin allow-popups allow-modals"></iframe>');
1266
+                                                              $("#smstables").append($iframe);
1267
+                                                      } else if (extenlst == 'txt') {
1268
+                                                              $("#smstables").append(readtxtfile[mmsfilenamesp]);
1269
+                                                      } else if (extension == 'mp4') {
1270
+							      $("#smstables").append('<video width="100%" height="auto" controls><source id="uploadedmp4" src="'+ baseUrl +'"></video>');
1271
+						      } else if (extension == 'ogg') {
1272
+							      $("#smstables").append('<video width="100%" height="auto" controls><source id="uploadedogg" src="'+ baseUrl +'"></video>');
1273
+						      } else if (extension == 'avi') {
1274
+							      $("#smstables").append('<video width="100%" height="auto" controls><source id="uploadedavi" src="'+ baseUrl +'" type="video/avi"></video>');
1275
+						      } else if (extension == 'mpg' || extension == 'mpeg') {
1276
+							      $("#smstables").append('<video width="100%" height="auto" controls><source id="uploadedmpg" src="'+ baseUrl +'"></video>');
1277
+						      } else if (extension == 'wav' || extension == 'wave') {
1278
+							      $("#smstables").append('<audio width="100%" height="auto" controls><source id="uploadedwav" src="'+ baseUrl +'"></audio>');
1279
+						      } else if (extension == 'mp3') {
1280
+							      $("#smstables").append('<audio width="100%" height="auto" controls><source id="uploadedmp3" src="'+ baseUrl +'" type="audio/mp3"></audio>');
1281
+						      } else if (extension == 'midi') {
1282
+							      $("#smstables").append('<audio width="100%" height="auto" controls><source id="uploadedmidi" src="'+ baseUrl +'" type="audio/midi"></audio>');
1283
+						      }
1284
+
1285
+                                                      $("#smstables").show();
1286
+                                                      $("#mmsfoldersview").hide();
1287
+                                                   });
1288
+                                                });
1289
+
1290
+
1291
+                                                // Remove picked files
1292
+                                                $('[class*="indpckfldl"]').last().click(function() {
1293
+                                                    var userid = "<?php p($userId); ?>";
1294
+                                                    var baseUrl = OC.generateUrl("/apps/sms_relentless/user/removeupfile");
1295
+
1296
+                                                    var removedfilenameinit = $(this).closest('[class*="indgenpckfls"]').find('[class*="indivflpckd"]').text();
1297
+
1298
+                                                    var removedfilesplit = removedfilenameinit.split(") ");
1299
+                                                    var removedflnb = parseInt(removedfilesplit[0]);
1300
+
1301
+                                                    $(this).closest('[class*="indgenpckfls"]').find('[class*="indivflpckd"]').hide();
1302
+                                                    $(this).hide();
1303
+                                                    var removedfilename = removedfilenameinit.substring(removedfilenameinit.indexOf(" ") + 1);
1304
+
1305
+                                                    uploadedtomms = $.grep(uploadedtomms, function(value) {
1306
+                                                             return value != removedfilename;
1307
+                                                    });
1308
+
1309
+                                                    $.ajax({
1310
+                                                        url: baseUrl + '/' + userid,
1311
+                                                        type: "POST",
1312
+                                                        data: {removedfilename: removedfilename},
1313
+                                                        success: function(totalflsize) {
1314
+
1315
+                                                             msgtotalflsize = totalflsize;
1316
+                                                             $('#filessizetext').text(totalflsize);
1317
+                                                             adjustMaximumSize(uploadedtomms);
1318
+
1319
+                                                             // Check message size
1320
+                                                             var rectotfilesz = parseFloat(totalflsize);
1321
+
1322
+                                                             if (rectotfilesz > maximumsize) {
1323
+                                                                 $('#filestotsize').css('color', '#ba3555');
1324
+                                                                 showAlert("Error ! For "+ chosenProvFullName +", for the chosen files format, the size of all the included files plus the size of the text cannot exceed "+ maximumsize +" KB !");
1325
+                                                                 $('#submitsms').attr("disabled", true);
1326
+                                                             } else {
1327
+                                                                 $('#submitsms').attr("disabled", false);
1328
+                                                                 $('#filestotsize').css('color', '#189558');
1329
+                                                               }
1330
+
1331
+                                                             // Rewrite order numbers for files that follow
1332
+                                                             --n;
1333
+                                                             $("div:visible[id*='indflpicked']").each(function() {
1334
+
1335
+                                                                  var getdivtext =  $(this).text();
1336
+                                                                  var splitdivtext = getdivtext.split(") ");
1337
+                                                                  var currentnbvalue = parseInt(splitdivtext[0]);
1338
+                                                                  var newnbvalue = currentnbvalue - 1;
1339
+
1340
+                                                                  if (currentnbvalue > removedflnb) {
1341
+                                                                      var replacedstr = newnbvalue + ") " + splitdivtext[1];
1342
+                                                                      $(this).text(replacedstr);
1343
+                                                                  }
1344
+                                                             });
1345
+                                                        },
1346
+                                                        error: function() {
1347
+                                                                  showAlert("Error while removing the file.");
1348
+                                                        }
1349
+                                                    });
1350
+
1351
+                                                    $('#smstables').removeClass('icon-loading');
1352
+                                                    $("#smstables").empty();
1353
+                                                });
1354
+
1355
+
1356
+		                                // Preview the picked file
1357
+		                                $("#mmsfoldersview").css("display", "inline-block");
1358
+		                                var flUrl = firstPathEl+"/remote.php/webdav/SMS_Relentless/temp_files/"+mmsfilename;
1359
+		                                var pickUrl = OC.generateUrl("/apps/sms_relentless/user/getpickedfile");
1360
+
1361
+                                                $("#smstables").empty();
1362
+                                                $("#stopAutoRefreshRec,#stopAutoRefreshSent").css("display", "none");
1363
+
1364
+						if (extension == 'jpg' || extension == 'jpeg') {
1365
+
1366
+		                                            $("#smstables").append('<img style="width:auto;height:auto" id="uploadedjpg" src="'+ flUrl +'" />');
1367
+
1368
+		                                } else if (extension == 'png') {
1369
+
1370
+		                                            $("#smstables").append('<img style="width:auto;height:auto" id="uploadedpng" src="'+ flUrl +'" />');
1371
+
1372
+		                                } else if (extension == 'gif') {
1373
+
1374
+		                                            $("#smstables").append('<img style="width:auto;height:auto" id="uploadedgif" src="'+ flUrl +'" />');
1375
+
1376
+		                                } else if (extension == 'bmp') {
1377
+
1378
+		                                            $("#smstables").append('<img style="width:auto;height:auto" id="uploadedbmp" src="'+ flUrl +'" />');
1379
+
1380
+		                                } else if (extension == 'tif' || extension == 'tiff') {
1381
+
1382
+		                                       var tiffile = '/remote.php/webdav/SMS_Relentless/temp_files/'+mmsfilename;
1383
+		                                       var xhr = new XMLHttpRequest();
1384
+		                                       xhr.responseType = 'arraybuffer';
1385
+		                                       xhr.open('GET', tiffile);
1386
+		                                       xhr.onload = function (event) {
1387
+		                                           var tiff = new Tiff({buffer: xhr.response});
1388
+		                                           var tifcanvas = tiff.toCanvas();
1389
+		                                           $("#smstables").append(tifcanvas);
1390
+		                                       };
1391
+		                                       xhr.send();
1392
+
1393
+		                                } else if (extension == 'pdf') {
1394
+
1395
+		                                       var viewer = OC.generateUrl('/apps/files_pdfviewer/?file={file}', {file: flUrl});
1396
+		                                       var $iframe = $('<iframe id="docviewer" style="width:100%;height:100%;display:block;position:absolute;top:0;left:0;z-index:1041;" src="' + viewer + '" sandbox="allow-scripts allow-same-origin allow-popups allow-modals"></iframe>');
1397
+		                                       $("#smstables").append($iframe);
1398
+
1399
+		                                } else if (extension == 'txt') {
1400
+
1401
+							     $.get(flUrl, function(textdata) {
1402
+		                                               readtxtfile[mmsfilename] = textdata.replace(/(?:\r\n|\r|\n)/g, '<br>');
1403
+							       $("#smstables").append(readtxtfile[mmsfilename]);
1404
+							     });
1405
+
1406
+		                                } else if (extension == 'mp4') {
1407
+						       $("#smstables").append('<video width="100%" height="auto" controls><source id="uploadedmp4" src="'+ baseUrl +'"></video>');
1408
+						} else if (extension == 'ogg') {
1409
+						       $("#smstables").append('<video width="100%" height="auto" controls><source id="uploadedogg" src="'+ baseUrl +'"></video>');
1410
+						} else if (extension == 'avi') {
1411
+						       $("#smstables").append('<video width="100%" height="auto" controls><source id="uploadedavi" src="'+ baseUrl +'" type="video/avi"></video>');
1412
+						} else if (extension == 'mpg' || extension == 'mpeg') {
1413
+						       $("#smstables").append('<video width="100%" height="auto" controls><source id="uploadedmpg" src="'+ baseUrl +'"></video>');
1414
+						} else if (extension == 'wav' || extension == 'wave') {
1415
+						       $("#smstables").append('<audio width="100%" height="auto" controls><source id="uploadedwav" src="'+ baseUrl +'"></audio>');
1416
+						} else if (extension == 'mp3') {
1417
+						       $("#smstables").append('<audio width="100%" height="auto" controls><source id="uploadedmp3" src="'+ baseUrl +'" type="audio/mp3"></audio>');
1418
+						} else if (extension == 'midi') {
1419
+						       $("#smstables").append('<audio width="100%" height="auto" controls><source id="uploadedmidi" src="'+ baseUrl +'" type="audio/midi"></audio>');
1420
+						}
1421
+
1422
+
1423
+		                                $("#smstables").show();
1424
+
1425
+		                                $('#pf_choose_msg').hide();
1426
+		                                $('#smstables').removeClass('icon-loading');
1427
+		                                $("#mmsfoldersview").hide();
1428
+
1429
+                                          },
1430
+
1431
+                                          error: function(data){
1432
+                                                      showAlert("Error while getting the file.");
1433
+                                          }
1434
+
1435
+                                       });
1436
+
1437
+                                    } else {
1438
+                                        showAlert("Error ! You cannot send more than "+ maximumfilenumber +" files in one MMS message !");
1439
+                                        $('#pf_choose_msg').hide();
1440
+                                        $('#smstables').removeClass('icon-loading');
1441
+                                      }
1442
+                                 } else {
1443
+                                      showAlert("Error ! There is already a file named '"+ mmsfilename +"' in the 'SMS_Relentless/temp_files' folder !");
1444
+                                      $('#pf_choose_msg').hide();
1445
+                                      $('#smstables').removeClass('icon-loading');
1446
+                                   }
1447
+
1448
+                              } else {
1449
+                                   showAlert("The file type is not supported! Supported extensions for "+ chosenProvFullName +" are: "+ validExtensions.join(", ") +".");
1450
+                                   $('#pf_choose_msg').hide();
1451
+                                   $('#smstables').removeClass('icon-loading');
1452
+                                }
1453
+
1454
+                        }
1455
+                );
1456
+  });
1457
+
1458
+
1459
+
1460
+  // Send the SMS/MMS message
1461
+  $("#submitsms").on("click", function(event) {
1462
+
1463
+     if (isMMS == 0) { var sendingtype = 'SMS'; } else { var sendingtype = 'MMS'; }
1464
+     OC.msg.startAction("#sms_submit_msg", t("sms_relentless", "Sending "+ sendingtype +" ... Please wait !"));
1465
+     $("#sms_submit_msg").css("display", "inline-block");
1466
+     $('#smstables,#recSmsTable,#sentSmsTable').addClass('icon-loading');
1467
+
1468
+     if (selectedid != '') { 
1469
+
1470
+         var sendersplit = selectedid.split(":");
1471
+         var providercap = sendersplit[0];
1472
+         var provsec = sendersplit[1];
1473
+
1474
+         if (/[a-zA-Z]/.test(provsec)) {
1475
+             var alphanumcheck = true;
1476
+         } else { var alphanumcheck = false; }
1477
+
1478
+         if (providercap == 'Tx' && alphanumcheck == false) {  
1479
+             var senderproc = selectedid.replace(/[^0-9]/g, "");
1480
+             var selectedsender = "+" + senderproc;
1481
+             var providerUsed = "telnyx";
1482
+             var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmstel");
1483
+         } else if (providercap == 'Pl' && alphanumcheck == false) {
1484
+             var selectedsender = selectedid.replace(/[^0-9]/g, "");
1485
+             var providerUsed = "plivo";
1486
+             var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmsnex");
1487
+         } else if (providercap == 'Tw' && alphanumcheck == false) {  
1488
+             var senderproc = selectedid.replace(/[^0-9]/g, "");
1489
+             var selectedsender = "+" + senderproc;
1490
+             var providerUsed = "twilio";
1491
+             var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmstwil");
1492
+         } else if (providercap == 'Fl' && alphanumcheck == false) {  
1493
+             var senderproc = selectedid.replace(/[^0-9]/g, "");
1494
+             var selectedsender = "+" + senderproc;
1495
+             var providerUsed = "flowroute";
1496
+             var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmsflow");
1497
+         } else if (providercap == 'Tx' && alphanumcheck == true) {
1498
+             var selectedsender = provsec;
1499
+             var providerUsed = "telnyx";
1500
+             var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmstel");
1501
+         } else if (providercap == 'Pl' && alphanumcheck == true) {
1502
+             var selectedsender = provsec;
1503
+             var providerUsed = "plivo";
1504
+             var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmsnex");
1505
+         } else if (providercap == 'Tw' && alphanumcheck == true) {
1506
+             var selectedsender = provsec;
1507
+             var providerUsed = "twilio";
1508
+             var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmstwil");
1509
+         } else if (providercap == 'Fl' && alphanumcheck == true) {
1510
+             var selectedsender = provsec;
1511
+             var providerUsed = "flowroute";
1512
+             var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmsflow");
1513
+         }
1514
+
1515
+         // Get the interval between message consecutive sending requests, if it's the case
1516
+         if ($('#tomultchckbx').is(':checked')) {
1517
+
1518
+             var numbersfile = 1;
1519
+             var initinterval = $("#multsmsinterval").val();
1520
+             var secinterval = initinterval.replace(/[^0-9]/g, "");
1521
+
1522
+             if (secinterval != '') {
1523
+                 var tertinterval = parseInt(secinterval);
1524
+                     waittime = tertinterval;
1525
+             }
1526
+
1527
+         } else {
1528
+
1529
+             var numbersfile = 0;
1530
+             var toNumberinit = $('#smsto').val();
1531
+             var toNumber = toNumberinit.replace(/[^0-9,]/g, "");
1532
+             var toNumbersec = toNumber.split(",");
1533
+
1534
+                 for (var i = 0; i < toNumbersec.length; i++) {
1535
+                      toNumbersec[i] = "+" + toNumbersec[i];
1536
+                 }
1537
+
1538
+                 receiversNumbers = toNumbersec.filter(function(v){return v!==""});
1539
+         }
1540
+
1541
+         if (numbersfile == 0 && $('#smsto').val().trim() == '') { receiversNumbers.length = 0; }
1542
+
1543
+         var smstext = $("#smstext").val();
1544
+
1545
+         if (receiversNumbers.length != 0) {
1546
+
1547
+              if (smstext != '') {
1548
+                  $.ajax({
1549
+                     url: relbaseUrl + '/' + userid,
1550
+                     type: "POST",
1551
+                     data: {
1552
+                           receiversPhoneNbs: receiversNumbers,
1553
+                           fromsender: selectedsender,
1554
+                           waitinterval: waittime,
1555
+                           sentsmstext: smstext,
1556
+                           ismms: isMMS,
1557
+                           mmsfiles: uploadedtomms
1558
+                         },
1559
+                     success: function() {
1560
+
1561
+                           if (receiversNumbers.length == 1) {
1562
+                                   showAlert("The message has been sent ! You can press the 'Sent Messages' button to check the current status and the delivery receipt for this message. If they don't appear immediately, wait about 10 seconds and press the button again.");
1563
+                           } else {
1564
+                                   showAlert("The messages have been sent ! You can press the 'Sent Messages' button to check the current status and the delivery receipt for each message. If they don't appear immediately, wait about 10 seconds and press the button again.");
1565
+                           }
1566
+
1567
+                           $('#sms_submit_msg').hide();
1568
+                           $('#smstables,#recSmsTable,#sentSmsTable').removeClass('icon-loading');
1569
+                     },
1570
+                     error: function() {
1571
+                           showAlert("Error! Please check the recipient's phone number and your settings!");
1572
+                           $('#sms_submit_msg').hide();
1573
+                           $('#smstables,#recSmsTable,#sentSmsTable').removeClass('icon-loading');
1574
+                     }
1575
+                  });
1576
+              } else {
1577
+                     showAlert("Please enter a message in the text box !");
1578
+
1579
+                     $('#sms_submit_msg').hide();
1580
+                     $('#smstables,#recSmsTable,#sentSmsTable').removeClass('icon-loading');
1581
+              }
1582
+         } else if (receiversNumbers.length == 0 && !($('#tomultchckbx').is(':checked'))) {
1583
+                 showAlert("Please enter the recipient's phone number !");
1584
+                 $('#sms_submit_msg').hide();
1585
+                 $('#smstables,#recSmsTable,#sentSmsTable').removeClass('icon-loading');
1586
+         } else if (receiversNumbers.length == 0 && $('#tomultchckbx').is(':checked')) {
1587
+                 showAlert("Please upload a txt or csv file that contains phone numbers separated by commas, semicolons, vertical bars or new lines !");
1588
+                 $('#sms_submit_msg').hide();
1589
+                 $('#smstables,#recSmsTable,#sentSmsTable').removeClass('icon-loading');
1590
+         }
1591
+     } else {
1592
+           showAlert("Please choose a Sender ID from the Set ID drop-down list !");
1593
+           $("#induploadfile").remove();
1594
+           $('#smstables,#recSmsTable,#sentSmsTable').removeClass('icon-loading');
1595
+           $('#sms_submit_msg').hide();
1596
+     }
1597
+
1598
+  });
1599
+
1600
+  // Check the checkbox to delete old messages from the database
1601
+  $('#deleteoldchckbox').change(function() {
1602
+     if ($(this).is(':checked')) {
1603
+         $("#deleteoldsms").css("display", "block");
1604
+     } else {
1605
+         $("#deleteoldsms").css("display", "none");
1606
+     }
1607
+  });
1608
+
1609
+  // Set the height of info notes
1610
+  $('#setcalleridtp').css('height', $(window).height() - 160);
1611
+  $('#tonmbrformat').css('height', $(window).height() - 260);
1612
+  $('#uploadfileinfo').css('height', $(window).height() - 390);
1613
+
1614
+  $(window).resize(function() { 
1615
+     $('#setcalleridtp').css('height', $(window).height() - 160);
1616
+     $('#tonmbrformat').css('height', $(window).height() - 260);
1617
+     $('#uploadfileinfo').css('height', $(window).height() - 390);
1618
+  });
1619
+
1620
+
1621
+  function showAlert(alertText) {
1622
+
1623
+     $("#alertMsgOverlay").remove();
1624
+     $("#alertMessage").remove();
1625
+
1626
+     let alertwnd = "<div id='alertMessage'>";
1627
+     alertwnd += "<a id='closeAlertWnd' title='Close this window'></a>";
1628
+     alertwnd += "<div id='alertTextWrap'>"+ alertText +"</div>";
1629
+     alertwnd += "<input type='submit' id='alertOk' value='OK'>";
1630
+     alertwnd += "</div>";
1631
+
1632
+     $("#content").append("<div id='alertMsgOverlay'></div>");
1633
+     $("#content").append(alertwnd);
1634
+
1635
+     let topDist = parseInt((window.innerHeight / 2).toFixed(2) - 152) +"px";
1636
+     let leftDist = parseInt((window.innerWidth / 2).toFixed(2) - 150) +"px";
1637
+     $("#alertMessage").css({ "top" : topDist, "left" : leftDist });
1638
+
1639
+     $("#closeAlertWnd").click(function() { $("#alertMsgOverlay").remove(); $("#alertMessage").remove(); });
1640
+     $("#alertMsgOverlay").click(function() { $("#alertMsgOverlay").remove(); $("#alertMessage").remove(); });
1641
+     $("#alertOk").click(function() { $("#alertMsgOverlay").remove(); $("#alertMessage").remove(); });
1642
+  }
0 1643
new file mode 100644
... ...
@@ -0,0 +1,911 @@
1
+/**
2
+ * @copyright 2021 Double Bastion LLC <www.doublebastion.com>
3
+ *
4
+ * @author Double Bastion LLC
5
+ *
6
+ * @license GNU AGPL version 3 or any later version
7
+ *
8
+ * This program is free software; you can redistribute it and/or
9
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
10
+ * License as published by the Free Software Foundation; either
11
+ * version 3 of the License, or any later version.
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
17
+ *
18
+ * You should have received a copy of the GNU Affero General Public
19
+ * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
+ *
21
+ */
22
+
23
+$(document).ready(function() {
24
+
25
+  var userid = "<?php p($userId); ?>";
26
+  var isadm = '';
27
+  var ctappdir = 'apps';
28
+
29
+  // Get app directory
30
+  var getappdirurl = OC.generateUrl('/apps/sms_relentless/user/getappdirectory');
31
+
32
+  $.ajax({
33
+     method: 'GET',
34
+     url: getappdirurl + '/' + userid,
35
+     contentType: 'application/json',
36
+     success: function(appdirfdb) {
37
+
38
+                  ctappdir = appdirfdb;
39
+
40
+		  // Get personal settings
41
+		  var baseUrlget = OC.generateUrl('/apps/sms_relentless/user/getsettings');
42
+
43
+		  $.ajax({
44
+		     method: 'GET',
45
+		     url: baseUrlget + '/' + userid,
46
+		     contentType: 'application/json',
47
+		     success: function(settingsfromdb) {
48
+
49
+			 // Add the webhook URLs section, if the user is not an admin
50
+			 if (settingsfromdb.adminornot == 'reguser') {
51
+
52
+			     isadm = 'reguser';
53
+
54
+			     $("#appTitlePrg").append('<p id="settings-dscr"><h3>Enter your options in the fields from below. As a non-admin user, you can use any of the SMS service providers from \
55
+				  below (Telnyx/Plivo/Twilio/Flowroute), on the condition that an admin has shared with you his API keys for that provider. If an admin has shared with you his API \
56
+				  keys for a provider, to be able to use them properly, you will have to generate the two webhook URLs for that provider by clicking the corresponding \
57
+				  "Generate new webhook URL ..." buttons from below, then click "Save" at the bottom of this page:</h3></p><br>');
58
+
59
+			     $("#nadmProvSection").append('<div class="providerSettings"><p><label for="telapi_url_rec" class="setlabeltext"><b>Telnyx webhook URL for incoming SMS/MMS</b> (Generate \
60
+				  the URL by pressing the button from below. Don\'t forget to also click the \'Save\' button at the bottom of this page after entering all the options, to save \
61
+				  all the settings to the database.)</label></p> \
62
+				  <input type="button" id="generate_tel_rcpt" class="generateUrl" value="Generate new webhook URL for incoming SMS/MMS" /> \
63
+				  <input type="text" class="smsr_textboxspec" id="telapi_url_rec" name="telapi_url_rec" autocomplete="false" /> \
64
+				  <span id="copyToClipboardtel" class="icon icon-clippy" title="Copy to clipboard"></span><br><br> \
65
+				  \
66
+				  <p><label for="telapi_url" class="setlabeltext"><b>Telnyx webhook URL for delivery receipts</b> (This URL will be included by SMS Relentless in message sending \
67
+				  requests, so that Telnyx will know where to send the delivery receipts. Just generate it by pressing the button from below. Don\'t forget to click the \'Save\' \
68
+				  button at the bottom of this page after entering all the options, to save all the settings to the database.)</label></p> \
69
+				  <input type="button" id="generate_tel_delrcpt" class="generateUrl" value="Generate new webhook URL for delivery receipts" /> \
70
+				  <input type="text" id="telapi_url" name="telapi_url" autocomplete="false" /></div><br><br> \
71
+				  \
72
+				  <div class="providerSettings"><p><label for="nexapi_url_rec" class="setlabeltext"><b>Plivo webhook URL for incoming SMS/MMS</b> (Generate the URL by pressing \
73
+				  the button from below. Don\'t forget to also click the \'Save\' button at the bottom of this page after entering all the options, to save all the settings \
74
+				  to the database.)</label></p> \
75
+				  <input type="button" id="generate_nex_rcpt" class="generateUrl" value="Generate new webhook URL for incoming SMS/MMS" /> \
76
+				  <input type="text" class="smsr_textboxspec" id="nexapi_url_rec" name="nexapi_url_rec" autocomplete="false" /> \
77
+				  <span id="copyToClipboardnex" class="icon icon-clippy" title="Copy to clipboard"></span><br><br> \
78
+				  \
79
+				  <p><label for="nexapi_url" class="setlabeltext"><b>Plivo webhook URL for delivery receipts</b> (This URL will be included by SMS Relentless in message sending \
80
+				  requests, so that Plivo will know where to send the delivery receipts. Just generate it by pressing the button from below. Don\'t forget to click the \'Save\' \
81
+				  button at the bottom of this page after entering all the options, to save all the settings to the database.)</label></p> \
82
+				  <input type="button" id="generate_nex_delrcpt" class="generateUrl" value="Generate new webhook URL for delivery receipts" /> \
83
+				  <input type="text" id="nexapi_url" name="nexapi_url" autocomplete="false" /></div><br><br> \
84
+				  \
85
+				  <div class="providerSettings"><p><label for="twilapi_url_rec" class="setlabeltext"><b>Twilio webhook URL for incoming SMS/MMS</b> (Generate the URL by pressing \
86
+				  the button from below. Don\'t forget to also click the \'Save\' button at the bottom of this page after entering all the options, to save all the settings to \
87
+				  the database.)</label></p> \
88
+				  <input type="button" id="generate_twil_rcpt" class="generateUrl" value="Generate new webhook URL for incoming SMS/MMS" /> \
89
+				  <input type="text" class="smsr_textboxspec" id="twilapi_url_rec" name="twilapi_url_rec" autocomplete="false" /> \
90
+				  <span id="copyToClipboardtwil" class="icon icon-clippy" title="Copy to clipboard"></span><br><br> \
91
+				  \
92
+				  <p><label for="twilapi_url" class="setlabeltext"><b>Twilio webhook URL for delivery receipts</b> (This URL will be included by SMS Relentless in message sending \
93
+				  requests, so that Twilio will know where to send the delivery receipts. Just generate it by pressing the button from below. Don\'t forget to click the \'Save\' \
94
+				  button at the bottom of this page after entering all the options, to save all the settings to the database.)</label></p> \
95
+				  <input type="button" id="generate_twil_delrcpt" class="generateUrl" value="Generate new webhook URL for delivery receipts" /> \
96
+				  <input type="text" id="twilapi_url" name="twilapi_url" autocomplete="false" /></div><br><br> \
97
+				  \
98
+				  <div class="providerSettings"><p><label for="flowapi_url_rec" class="setlabeltext"><b>Flowroute webhook URL for incoming SMS/MMS</b> (Generate the URL by pressing \
99
+				  the button from below. Don\'t forget to also click the \'Save\' button at the bottom of this page after entering all the options, to save all the settings to \
100
+				  the database.)</label></p> \
101
+				  <input type="button" id="generate_flow_rcpt" class="generateUrl" value="Generate new webhook URL for incoming SMS/MMS" /> \
102
+				  <input type="text" class="smsr_textboxspec" id="flowapi_url_rec" name="flowapi_url_rec" autocomplete="false" /> \
103
+				  <span id="copyToClipboardflow" class="icon icon-clippy" title="Copy to clipboard"></span><br><br> \
104
+				  \
105
+				  <p><label for="flowapi_url" class="setlabeltext"><b>Flowroute webhook URL for delivery receipts</b> (This URL will be included by SMS Relentless in message sending \
106
+				  requests, so that Flowroute will know where to send the delivery receipts. Just generate it by pressing the button from below. Don\'t forget to click the \'Save\' \
107
+				  button at the bottom of this page after entering all the options, to save all the settings to the database.)</label></p> \
108
+				  <input type="button" id="generate_flow_delrcpt" class="generateUrl" value="Generate new webhook URL for delivery receipts" /> \
109
+				  <input type="text" id="flowapi_url" name="flowapi_url" autocomplete="false" /><br><br> \
110
+				  Flowroute only supports sending/receiving SMS/MMS messages within USA and Canada and it doesn\'t support Alphanumeric Sender IDs.</div><br>');
111
+
112
+
113
+				  $("#telapi_url_rec").val(settingsfromdb.telapi_url_rec);
114
+				  $("#telapi_url").val(settingsfromdb.telapi_url);
115
+				  $("#nexapi_url_rec").val(settingsfromdb.nexapi_url_rec);
116
+				  $("#nexapi_url").val(settingsfromdb.nexapi_url);
117
+				  $("#twilapi_url_rec").val(settingsfromdb.twilapi_url_rec);
118
+				  $("#twilapi_url").val(settingsfromdb.twilapi_url);
119
+				  $("#flowapi_url_rec").val(settingsfromdb.flowapi_url_rec);
120
+				  $("#flowapi_url").val(settingsfromdb.flowapi_url);
121
+				  $("#messagesperpage").val(settingsfromdb.messagesperpage);
122
+				  $("#msgcheckinterval").val(settingsfromdb.msg_check_interval);
123
+
124
+				  if (settingsfromdb.get_notify == 1) {
125
+				      $("#get_notify").attr('checked', true);
126
+				  } else {
127
+				      $("#get_notify").attr('checked', false);
128
+				  }
129
+
130
+				  $("#notification_email").val(settingsfromdb.notification_email);
131
+
132
+				  if (settingsfromdb.getsmsinemail == 1) {
133
+				      $("#includesmsinemail").attr('checked', true);
134
+				  } else {
135
+				      $("#includesmsinemail").attr('checked', false);
136
+				  }
137
+
138
+				  if (settingsfromdb.show_display_names == 1) {
139
+				      $("#showdisplaynames").attr('checked', true);
140
+				  } else {
141
+				      $("#showdisplaynames").attr('checked', false);
142
+				  }
143
+
144
+				  if (settingsfromdb.add_display_names == 1) {
145
+				      $("#adddisplaynames").attr('checked', true);
146
+				  } else {
147
+				      $("#adddisplaynames").attr('checked', false);
148
+				  }
149
+
150
+				  function randomStr(strlength) {
151
+					var fintext = "";
152
+					var keyspace = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
153
+					for (var i = 0; i < strlength; i++) {
154
+					     fintext += keyspace.charAt(Math.floor(Math.random() * keyspace.length));
155
+					}
156
+					return fintext;
157
+				  }
158
+
159
+				  $("#generate_tel_rcpt").on("click", function(event) {
160
+
161
+				     var teltokenrec = randomStr(70);
162
+				     var telnyxwhurlrec = window.location.origin + OC.generateUrl('/apps/sms_relentless/api/recsmstel?telrecparam=') + teltokenrec;
163
+
164
+				     $("#telapi_url_rec").val(telnyxwhurlrec);
165
+				  });
166
+
167
+				  $("#copyToClipboardtel").on("click", function(event) {
168
+				     var $tempEl = $("<input>");
169
+				     $("body").append($tempEl);
170
+				     $tempEl.val($("#telapi_url_rec").val()).select();
171
+				     document.execCommand("Copy");
172
+				     $tempEl.remove();
173
+				     showAlert("The link has been copied to your clipboard!");
174
+				  });
175
+
176
+				  $("#generate_tel_delrcpt").on("click", function(event) {
177
+
178
+				     var teltoken = randomStr(70);
179
+				     var telnyxwhurl = window.location.origin + OC.generateUrl('/apps/sms_relentless/api/recdeliverytel?teldrparam=') + teltoken;
180
+
181
+				     $("#telapi_url").val(telnyxwhurl);
182
+				  });
183
+
184
+
185
+				  $("#generate_nex_rcpt").on("click", function(event) {
186
+
187
+				     var plivotokenrec = randomStr(70);
188
+				     var plivowhurlrec = window.location.origin + OC.generateUrl('/apps/sms_relentless/api/recsmsnex?plivorecparam=') + plivotokenrec;
189
+
190
+				     $("#nexapi_url_rec").val(plivowhurlrec);
191
+				  });
192
+
193
+				  $("#copyToClipboardnex").on("click", function(event) {
194
+				     var $tempElpl = $("<input>");
195
+				     $("body").append($tempElpl);
196
+				     $tempElpl.val($("#nexapi_url_rec").val()).select();
197
+				     document.execCommand("Copy");
198
+				     $tempElpl.remove();
199
+				     showAlert("The link has been copied to your clipboard!");
200
+				  });
201
+
202
+				  $("#generate_nex_delrcpt").on("click", function(event) {
203
+
204
+				     var plivotoken = randomStr(70);
205
+				     var plivodrwhurl = window.location.origin + OC.generateUrl('/apps/sms_relentless/api/recdeliverynex?plivodrparam=') + plivotoken;
206
+
207
+				     $("#nexapi_url").val(plivodrwhurl);
208
+				  });
209
+
210
+
211
+				  $("#generate_twil_rcpt").on("click", function(event) {
212
+
213
+				     var twiltokenrec = randomStr(35);
214
+				     var twilwhurlrec = window.location.origin + OC.generateUrl('/apps/sms_relentless/api/recsmstwil?twilrecparam=') + twiltokenrec;
215
+
216
+				     $("#twilapi_url_rec").val(twilwhurlrec);
217
+				  });
218
+
219
+				  $("#copyToClipboardtwil").on("click", function(event) {
220
+				     var $tempElpl = $("<input>");
221
+				     $("body").append($tempElpl);
222
+				     $tempElpl.val($("#twilapi_url_rec").val()).select();
223
+				     document.execCommand("Copy");
224
+				     $tempElpl.remove();
225
+				     showAlert("The link has been copied to your clipboard!");
226
+				  });
227
+
228
+				  $("#generate_twil_delrcpt").on("click", function(event) {
229
+
230
+				     var twiltoken = randomStr(35);
231
+				     var twildrwhurl = window.location.origin + OC.generateUrl('/apps/sms_relentless/api/recdeliverytwil?twildrparam=') + twiltoken;
232
+
233
+				     $("#twilapi_url").val(twildrwhurl);
234
+				  });
235
+
236
+
237
+				  $("#generate_flow_rcpt").on("click", function(event) {
238
+
239
+				     var flowtokenrec = randomStr(70);
240
+				     var flowwhurlrec = window.location.origin + OC.generateUrl('/apps/sms_relentless/api/recsmsflow?flowrecparam=') + flowtokenrec;
241
+
242
+				     $("#flowapi_url_rec").val(flowwhurlrec);
243
+				  });
244
+
245
+				  $("#copyToClipboardflow").on("click", function(event) {
246
+				     var $tempElpl = $("<input>");
247
+				     $("body").append($tempElpl);
248
+				     $tempElpl.val($("#flowapi_url_rec").val()).select();
249
+				     document.execCommand("Copy");
250
+				     $tempElpl.remove();
251
+				     showAlert("The link has been copied to your clipboard!");
252
+				  });
253
+
254
+				  $("#generate_flow_delrcpt").on("click", function(event) {
255
+
256
+				     var flowtoken = randomStr(70);
257
+				     var flowdrwhurl = window.location.origin + OC.generateUrl('/apps/sms_relentless/api/recdeliveryflow?flowdrparam=') + flowtoken;
258
+
259
+				     $("#flowapi_url").val(flowdrwhurl);
260
+				  });
261
+
262
+
263
+			 } else if (settingsfromdb.adminornot == 'admin') {
264
+
265
+				  $("#appTitlePrg").append('<p id="settings-dscr"><h3>First enter your credentials on the admin settings page of the app (on the left panel, under Administration, \
266
+				                            click on SMS Relentless), then enter your options in the fields from below:</h3></p><br>');
267
+				  isadm = 'admin';
268
+
269
+				  $("#messagesperpage").val(settingsfromdb.messagesperpage);
270
+				  $("#msgcheckinterval").val(settingsfromdb.msg_check_interval);
271
+
272
+				  if (settingsfromdb.get_notify == 1) {
273
+				      $("#get_notify").attr('checked', true);
274
+				  } else {
275
+				      $("#get_notify").attr('checked', false);
276
+				  }
277
+
278
+				  $("#notification_email").val(settingsfromdb.notification_email);
279
+
280
+				  if (settingsfromdb.getsmsinemail == 1) {
281
+				      $("#includesmsinemail").attr('checked', true);
282
+				  } else {
283
+				      $("#includesmsinemail").attr('checked', false);
284
+				  }
285
+
286
+				  if (settingsfromdb.show_display_names == 1) {
287
+				      $("#showdisplaynames").attr('checked', true);
288
+				  } else {
289
+				      $("#showdisplaynames").attr('checked', false);
290
+				  }
291
+
292
+				  if (settingsfromdb.add_display_names == 1) {
293
+				      $("#adddisplaynames").attr('checked', true);
294
+				  } else {
295
+				      $("#adddisplaynames").attr('checked', false);
296
+				  }
297
+			 }
298
+
299
+
300
+			 // Auto-reply settings
301
+
302
+			 // Get the available phone numbers from all providers associated with the access keys entered on the Settings page (restrictions are applied to numbers for non-admins)
303
+			 $("#autoRplPhoneNb").addClass('icon-loading');
304
+			 var getnumbersUrl = OC.generateUrl("/apps/sms_relentless/user/getautoreplyconf");
305
+
306
+			 $.ajax({
307
+				  url: getnumbersUrl + '/' + userid,
308
+				  type: "GET",
309
+				  contentType: 'application/json',
310
+				  success: function(autoreplydata) {
311
+
312
+				                    $("#autoRplPhoneNb").removeClass('icon-loading');
313
+				                    var cusrDisplayName = autoreplydata.userdisplayname;
314
+				                    var availPhoneNmbrs = autoreplydata.phonenumbers;
315
+				                    var autorpldata = autoreplydata.autoreplies;
316
+
317
+						    if (autorpldata.length > 0) { 
318
+							var arplNmb = autorpldata.length;
319
+						    } else { 
320
+							var arplNmb = 0; 
321
+						    }
322
+
323
+						    // List the auto-replies for the phone numbers available for the current user
324
+						    if (arplNmb == 0) {
325
+
326
+							$("#autoReplyTbl").append("<tr><td><input type='text' class='arplAuthor' value='"+ cusrDisplayName +"' disabled></td><td><select id='arpphn-"+ arplNmb +"' class='arplPhoneNmbr'></select></td><td><div id='arplmode-"+ arplNmb +"' class='arplMode'><select id='modeselect-"+ arplNmb +"' class='selectArplMode'><option value='' selected>Select mode</option><option value='daily'>Daily mode</option><option value='vacation'>Vacation mode</option></select><div id='modecont-"+ arplNmb +"' class='modeContent'></div></div></td><td><textarea id='arpltxt-"+ arplNmb +"' class='arplText' rows='20' cols='40' placeholder='Enter the auto-reply message here.'></textarea></td><td><img id='rmRow-"+ arplNmb +"' class='removeRow' src='/" + ctappdir + "/sms_relentless/img/closewnd.svg' title='Remove this row from the database' style='cursor:pointer;margin:9px 8px 0px 18px;'></td><td><input type='submit' id='arplsave-"+ arplNmb +"' class='saveAutoReply' value='Save' title='Save Row' /></td></tr>");
327
+							$("#autoReplyTbl").append("<div><img id='addArplRow' src='/" + ctappdir + "/sms_relentless/img/add.svg' title='Add Row'></div>");
328
+
329
+						    } else {
330
+
331
+							for (k = 0; k < arplNmb; k++) {
332
+
333
+				                             if (autorpldata[k].days_of_week != '') {
334
+
335
+				                                 var slctdMode = "<option value=''>Select mode</option><option value='daily' selected>Daily mode</option><option value='vacation'>Vacation mode</option>";
336
+				                                 var dailyStartArr = autorpldata[k].daily_start.split(":");
337
+				                                 var dailyEndArr = autorpldata[k].daily_end.split(":");
338
+
339
+						                 var dlHrStartOptions = "";
340
+							         for (var hr = 0; hr < 24; hr++) {
341
+						                      if (dailyStartArr[0] != hr.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false})) {
342
+							                  dlHrStartOptions += "<option value='"+ hr.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false}) +"'>"+ hr.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false}) +"</option>";
343
+						                      } else {
344
+							                  dlHrStartOptions += "<option value='"+ hr.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false}) +"' selected>"+ hr.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false}) +"</option>";
345
+						                      }
346
+							         }
347
+
348
+						                 var dlMnStartOptions = "";
349
+							         for (var mn = 0; mn < 60; mn++) {
350
+						                      if (dailyStartArr[1] != mn.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false})) {
351
+							                  dlMnStartOptions += "<option value='"+ mn.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false}) +"'>"+ mn.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false}) +"</option>";
352
+						                      } else {
353
+							                  dlMnStartOptions += "<option value='"+ mn.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false}) +"' selected>"+ mn.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false}) +"</option>";
354
+						                      }
355
+							         }
356
+
357
+						                 var dlHrEndOptions = "";
358
+							         for (var hr = 0; hr < 24; hr++) {
359
+						                      if (dailyEndArr[0] != hr.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false})) {
360
+							                  dlHrEndOptions += "<option value='"+ hr.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false}) +"'>"+ hr.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false}) +"</option>";
361
+						                      } else {
362
+							                  dlHrEndOptions += "<option value='"+ hr.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false}) +"' selected>"+ hr.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false}) +"</option>";
363
+						                      }
364
+							         }
365
+
366
+						                 var dlMnEndOptions = "";
367
+							         for (var mn = 0; mn < 60; mn++) {
368
+						                      if (dailyEndArr[1] != mn.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false})) {
369
+							                  dlMnEndOptions += "<option value='"+ mn.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false}) +"'>"+ mn.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false}) +"</option>";
370
+						                      } else {
371
+							                  dlMnEndOptions += "<option value='"+ mn.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false}) +"' selected>"+ mn.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false}) +"</option>";
372
+						                      }
373
+							         }
374
+
375
+				                                 var modeContent = "<div class='daysOfWeek'>Days of the week:<div class='tooltipautoreply'><div id='infoautoreply'>i</div><div class='autorpltooltip'>Enter the order number of the days of the week in which the auto-reply will be sent. For example, to send the auto-reply every day from Monday to Friday outside the time interval specified below, enter 1,2,3,4,5 To send the auto-reply only Monday, Thursday and Friday enter 1,4,5 To send the auto-reply every day of the week enter 1,2,3,4,5,6,7 As an exception, if you want the auto-reply to be sent during an entire day, irrespective of the specified interval, add (full) after the number of that day. For example, if you want the auto-reply to be sent from Monday to Friday outside the interval specified below, and also during the entire days of Saturday and Sunday, enter 1,2,3,4,5,6(full),7(full)</div></div></div><input type='text' id='weekdays-"+ k +"' class='daysInWeek' value='"+ autorpldata[k].days_of_week +"'><div class='chooseTInterval'>Send auto-reply <span style='color:#ad0202'>outside</span> this interval:<div class='tooltipautoreplyst'><div id='infoautoreplyst'>i</div><div class='autorpltooltipst'>These fields specify the time of the server. If the server is located in a time zone that is different from that of the owner/company, the time interval entered here should be adjusted accordingly.</div></div></div><div class='selectArplHours'><select id='dmstarthr-"+ k +"' class='selectHrMin'>"+ dlHrStartOptions +"</select><select id='dmstartmn-"+ k +"' class='selectHrMin'>"+ dlMnStartOptions +"</select><span style='font-weight: 600'> — </span><select id='dmendhr-"+ k +"' class='selectHrMin'>"+ dlHrEndOptions +"</select><select id='dmendmn-"+ k +"' class='selectHrMin'>"+ dlMnEndOptions +"</select></div>";
376
+
377
+				                             } else {
378
+
379
+				                                 var vctnStart = autorpldata[k].vacation_start.split(" ")[0];
380
+				                                 var vctnEnd = autorpldata[k].vacation_end.split(" ")[0];
381
+
382
+				                                 var slctdMode = "<option value=''>Select mode</option><option value='daily'>Daily mode</option><option value='vacation' selected>Vacation mode</option>";
383
+				                                 var modeContent = "<div class='chooseDateIntvl'>Send auto-reply <span style='color:#ad0202'>inside</span> this interval:</div><div class='arplstrtendDates'><div class='stdtTitle'>Start Date</div><input type='text' id='startDT-"+ k +"' class='startDate' placeholder='Pick a date' value='"+ vctnStart +"'><div class='enddtTitle'>End Date</div><input type='text' id='endDT-"+ k +"' class='endDate' placeholder='Pick a date' value='"+ vctnEnd +"'></div>"
384
+				                             }
385
+
386
+							     $("#autoReplyTbl").append("<tr><td><input type='text' class='arplAuthor' value='"+ autorpldata[k].saved_by_dsplname +"' disabled></td><td><select id='arpphn-"+ k +"' class='arplPhoneNmbr' style='pointer-events:none'><option selected>"+ autorpldata[k].phone_number +"</option></select></td><td><div id='arplmode-"+ k +"' class='arplMode'><select id='modeselect-"+ k +"' class='selectArplMode'>"+ slctdMode +"</select><div id='modecont-"+ k +"' class='modeContent'>"+ modeContent +"</div></div></td><td><textarea id='arpltxt-"+ k +"' class='arplText' rows='20' cols='40' placeholder='Enter the auto-reply message here.'>"+ autorpldata[k].message_text +"</textarea></td><td><img id='rmRow-"+ k +"' class='removeRow' src='/" + ctappdir + "/sms_relentless/img/closewnd.svg' title='Remove this row from the database' style='cursor:pointer;margin:9px 8px 0px 18px;'></td><td><input type='submit' id='arplsave-"+ k +"' class='saveAutoReply' value='Edit' title='Edit Row' /></td></tr>");
387
+							}
388
+							$("#autoReplyTbl").append("<div><img id='addArplRow' src='/" + ctappdir + "/sms_relentless/img/add.svg' title='Add Row'></div>");
389
+						    }
390
+
391
+
392
+						    // Create a list with all the available phone numbers
393
+				                    var numbersListItems = "<option value='' selected>Select phone number</option>";
394
+
395
+						    $.each(availPhoneNmbrs, function(key, indsmsnmb) {
396
+							   numbersListItems += "<option value='"+ indsmsnmb +"'>"+ indsmsnmb +"</option>";
397
+						    });
398
+
399
+				                    if (arplNmb == 0) {
400
+							$("#arpphn-"+ arplNmb).append(numbersListItems);
401
+				                    }
402
+
403
+				                    // Initialize the date picker
404
+						    $('[id^="endDT-"]').datepicker({ dateFormat: "yy-mm-dd" });
405
+						    $('[id^="startDT-"]').datepicker({ dateFormat: "yy-mm-dd" });
406
+
407
+
408
+				                    // Select the auto-reply mode
409
+				                    function selectMode() {
410
+
411
+						            $('[id^="modeselect-"]').change(function() {
412
+
413
+						               var crtnmbr = $(this).attr("id").replace("modeselect-", "");
414
+
415
+						               var dailyHrStart = "";
416
+						               for (var h = 0; h < 24; h++) {
417
+						                    dailyHrStart += "<option value='"+ h.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false}) +"'>"+ h.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false}) +"</option>";
418
+						               }
419
+
420
+						               var dailyMnStart = "";
421
+						               for (var m = 0; m < 60; m++) {
422
+						                    dailyMnStart += "<option value='"+ m.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false}) +"'>"+ m.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping:false}) +"</option>";
423
+						               }
424
+
425
+						               var dailyHrEnd = dailyHrStart;
426
+						               var dailyMnEnd = dailyMnStart;
427
+
428
+						               if ($(this).val() == 'daily') {
429
+						                   $("#modecont-"+ crtnmbr).empty();
430
+						                   $("#modecont-"+ crtnmbr).append("<div class='daysOfWeek'>Days of the week:<div class='tooltipautoreply'><div id='infoautoreply'>i</div><div class='autorpltooltip'>Enter the order number of the days of the week in which the auto-reply will be sent. For example, to send the auto-reply every day from Monday to Friday outside the time interval specified below, enter 1,2,3,4,5 To send the auto-reply only Monday, Thursday and Friday enter 1,4,5 To send the auto-reply every day of the week enter 1,2,3,4,5,6,7 As an exception, if you want the auto-reply to be sent during an entire day, irrespective of the specified interval, add (full) after the number of that day. For example, if you want the auto-reply to be sent from Monday to Friday outside the interval specified below, and also during the entire days of Saturday and Sunday, enter 1,2,3,4,5,6(full),7(full)</div></div></div><input type='text' id='weekdays-"+ crtnmbr +"' class='daysInWeek'><div class='chooseTInterval'>Send auto-reply <span style='color:#ad0202'>outside</span> this interval:<div class='tooltipautoreplyst'><div id='infoautoreplyst'>i</div><div class='autorpltooltipst'>These fields specify the time of the server. If the server is located in a time zone that is different from that of the owner/company, the time interval entered here should be adjusted accordingly.</div></div></div><div class='selectArplHours'><select id='dmstarthr-"+ crtnmbr +"' class='selectHrMin'>"+ dailyHrStart +"</select><select id='dmstartmn-"+ crtnmbr +"' class='selectHrMin'>"+ dailyMnStart +"</select><span style='font-weight: 600'> — </span><select id='dmendhr-"+ crtnmbr +"' class='selectHrMin'>"+ dailyHrEnd +"</select><select id='dmendmn-"+ crtnmbr +"' class='selectHrMin'>"+ dailyMnEnd +"</select></div>");
431
+						               } else if ($(this).val() == 'vacation') {
432
+						                   $("#modecont-"+ crtnmbr).empty();
433
+						                   $("#modecont-"+ crtnmbr).append("<div class='chooseDateIntvl'>Send auto-reply <span style='color:#ad0202'>inside</span> this interval:</div><div class='arplstrtendDates'><div class='stdtTitle'>Start Date</div><input type='text' id='startDT-"+ crtnmbr +"' class='startDate' placeholder='Pick a date'><div class='enddtTitle'>End Date</div><input type='text' id='endDT-"+ crtnmbr +"' class='endDate' placeholder='Pick a date' /></div>");
434
+						               }
435
+
436
+							       $("#endDT-"+ crtnmbr +"").datepicker({ dateFormat: "yy-mm-dd" });
437
+							       $("#startDT-"+ crtnmbr +"").datepicker({ dateFormat: "yy-mm-dd" });
438
+						          });
439
+				                  }
440
+				                  selectMode();
441
+
442
+						  // Save the data
443
+						  function saveArplRow() {
444
+
445
+						     $('[id^="arplsave-"]').unbind("click");
446
+						     $('[id^="arplsave-"]').click(function(event) {
447
+
448
+							event.preventDefault();
449
+							var crntrwnmbr = $(this).attr("id").replace("arplsave-", "");
450
+
451
+							if ($(this).attr("value") == "Save") {
452
+
453
+							    var phoneNmbr = $("#arpphn-"+ crntrwnmbr).val();
454
+							    var arplText = $("#arpltxt-"+ crntrwnmbr).val();
455
+							    var slctdMode = $("#modeselect-"+ crntrwnmbr).val();
456
+
457
+							    var slctddmDays = "";
458
+							    var slctdHrStart = "";
459
+							    var slctdMnStart = "";
460
+							    var slctdHrEnd = "";
461
+							    var slctdMnEnd = "";
462
+
463
+							    var vcStartDate = null;
464
+							    var vcEndDate = null;
465
+
466
+							    if (slctdMode == 'daily') {
467
+
468
+								slctddmDays = $("#weekdays-"+ crntrwnmbr).val().trim();
469
+								slctdHrStart = $("#dmstarthr-"+ crntrwnmbr).val().trim();
470
+								slctdMnStart = $("#dmstartmn-"+ crntrwnmbr).val().trim();
471
+								slctdHrEnd = $("#dmendhr-"+ crntrwnmbr).val().trim();
472
+								slctdMnEnd = $("#dmendmn-"+ crntrwnmbr).val().trim();
473
+
474
+				                                if (slctdHrStart != '' && slctdMnStart != '') {
475
+				                                    var hrmnStartComp = slctdHrStart +":"+ slctdMnStart;
476
+				                                } else { var hrmnStartComp = ""; }
477
+
478
+				                                if (slctdHrEnd != '' && slctdMnEnd != '') {
479
+				                                    var hrmnEndComp = slctdHrEnd +":"+ slctdMnEnd;
480
+				                                } else { var hrmnEndComp = ""; }
481
+
482
+				                                if (!(/^[1-7ful\,\(\)]+$/.test(slctddmDays))) {
483
+								    showAlert("The 'Days of the week' field can contain only digits from 1 to 7, the lowercase letters f, u and l, round brackets ()() and commas (,).");
484
+								    return;
485
+				                                }
486
+
487
+				                                if (!(/^[0-9]+$/.test(slctdHrStart + slctdMnStart + slctdHrEnd + slctdMnEnd))) {
488
+								    showAlert("The starting and ending values of the time interval for the 'Daily mode' can contain only digits from 0 to 9.");
489
+								    return;
490
+				                                }
491
+
492
+				                                if (slctddmDays.trim() == '' || (slctdHrStart == slctdHrEnd && slctdMnStart == slctdMnEnd)) {
493
+								    showAlert("For the 'Daily mode', you have to enter the order number of the days of the week for which you want the auto-reply to be sent, and you have to set a starting time that is different from the ending time!");
494
+								    return;
495
+				                                }
496
+
497
+							    } else if (slctdMode == 'vacation') {
498
+				
499
+				                                if ($("#startDT-"+ crntrwnmbr).val().trim() == '' || $("#endDT-"+ crntrwnmbr).val().trim() == '') {
500
+
501
+								    showAlert("For the 'Vacation mode', you have to enter both a start date and an end date.");
502
+								    return;
503
+
504
+				                                } else {
505
+
506
+				                                    if (!(/^[0-9\-]+$/.test($("#startDT-"+ crntrwnmbr).val().trim() + $("#endDT-"+ crntrwnmbr).val().trim()))) {
507
+								        showAlert("The start date and end date values for the 'Vacation mode' can contain only digits from 0 to 9 and hyphens (-).");
508
+								        return;
509
+				                                    }
510
+
511
+						                    vcStartDate = $("#startDT-"+ crntrwnmbr).val().trim() +" 00:00:00";
512
+								    vcEndDate = $("#endDT-"+ crntrwnmbr).val().trim() +" 23:59:59";
513
+								    var strtDateCmp = new Date(vcStartDate).toJSON().slice(0, 10) +" 00:00:00";
514
+								    var endDateCmp = new Date(vcEndDate).toJSON().slice(0, 10) +" 23:59:59";
515
+								    var crntDate = new Date().toJSON().slice(0, 10) +" 23:59:59";
516
+
517
+				                                    if (vcStartDate.trim() == "" || vcEndDate.trim() == "" || (strtDateCmp >= endDateCmp || ((strtDateCmp < crntDate) && (endDateCmp < crntDate)))) {
518
+								        showAlert("For 'Vacation mode', you have to enter both a start date and an end date, the start date must be before the end date and at least the ending of the time interval must be in the future.");
519
+								        return;
520
+				                                    }
521
+				                                }
522
+							    }
523
+
524
+
525
+							    if (phoneNmbr != '') {
526
+
527
+							      if (arplText.trim() != '') {
528
+
529
+								if (slctdMode != '') {
530
+
531
+								    var saveArplUrl = OC.generateUrl('/apps/sms_relentless/user/updateautoreplies');
532
+								    var arpldata = {
533
+								         userId: userid,
534
+								         savedByDsplname: cusrDisplayName,
535
+								         phoneNumber: phoneNmbr,
536
+								         daysOfWeek: slctddmDays,
537
+								         dailyStart: hrmnStartComp,
538
+								         dailyEnd: hrmnEndComp,
539
+								         vacationStart: vcStartDate,
540
+								         vacationEnd: vcEndDate,
541
+								         messageText: arplText
542
+								    };
543
+
544
+								    $.ajax({
545
+								      method: 'PUT',
546
+								      url: saveArplUrl + '/' + userid,
547
+								      contentType: 'application/json',
548
+								      data: JSON.stringify(arpldata),
549
+								      success: function(messagereceived) {
550
+
551
+								                   if (messagereceived == 'success') {
552
+								                       showAlert('The auto-reply has been successfully saved to the database!');
553
+								                   } else if (messagereceived == 'failure') {
554
+								                       showAlert('Error while trying to save the auto-reply!');
555
+								                   } else if (messagereceived == 'not allowed') {
556
+				                                                       showAlert('You cannot change an auto-reply that was saved by a different user.');
557
+				                                                   }
558
+								      },
559
+								      error: function() {
560
+										   showAlert('Error while attempting to save the auto-reply! You can check the Nextcloud log to find more details about this issue.');
561
+								      }
562
+								    });
563
+
564
+
565
+				                                } else { showAlert("Please select the auto-reply mode."); return; }
566
+
567
+				                              } else { showAlert("Please enter the text of the auto-reply."); return; }
568
+
569
+				                            } else { showAlert("Please select a phone number if at least one number is available in the 'Phone Number' drop-down list. Otherwise, you should contact the administrator."); return; }
570
+
571
+				                            $(this).attr("value", "Edit");
572
+
573
+				                        } else {
574
+				                            $("#arplsave-"+ crntrwnmbr).attr("value", "Save");
575
+				                        }
576
+
577
+				                     });
578
+
579
+						  }
580
+				                  saveArplRow();
581
+
582
+
583
+						  // Remove a row
584
+						  function removeArplRow() {
585
+						       $('[id^="rmRow-"]').click(function() {
586
+
587
+							  var slctRowRm = $(this).attr("id").replace("rmRow-", "");
588
+							  var crntPhnNmbr = $("#arpphn-"+ slctRowRm).val();
589
+
590
+							  confirmAlert("Do you really want to remove this row from the database ?");
591
+
592
+							  $("#confirmCancel").click(function() { $("#alertMsgOverlay").remove(); $("#alertConfMessage").remove(); });
593
+
594
+							  $("#confirmOk").click(function() {
595
+
596
+							      $("#alertMsgOverlay").remove();
597
+							      $("#alertConfMessage").remove();
598
+
599
+							      var rmvArplUrl = OC.generateUrl('/apps/sms_relentless/user/removeautoreplies');
600
+							      $.ajax({
601
+								   url: rmvArplUrl + '/' + userid,
602
+								   method: "POST",
603
+								   dataType: "text",
604
+								   data: { phoneNumber: crntPhnNmbr },
605
+								   success: function(delresult) {
606
+
607
+										     if (delresult.indexOf("success") > -1) {
608
+										         showAlert("The auto-reply has been removed successfully!");
609
+										         $("#arpphn-"+ slctRowRm).closest("tr").remove();
610
+										     } else if (delresult.indexOf("failure") > -1) {
611
+										         showAlert("Error while trying to remove auto-reply data!");
612
+										     } else if (delresult.indexOf("not allowed") > -1) {
613
+				                                                         showAlert("You cannot remove the auto-reply saved by another user.");
614
+				                                                     }
615
+								   },
616
+								   error: function() { showAlert("Error while attempting to remove auto-reply data! You can check the Nextcloud log to find more details about this issue."); }
617
+							       });
618
+							  });
619
+						       });
620
+						  }
621
+						  removeArplRow();
622
+
623
+				                  // Add a new row
624
+				                  $("#addArplRow").click(function() {
625
+
626
+				                     if ($("#autoReplyTbl").find("tr:last-child").find(".arplPhoneNmbr").length > 0) {
627
+				                         var lastarpl = $("#autoReplyTbl").find("tr:last-child").find(".arplPhoneNmbr").attr("id").replace("arpphn-", "");
628
+				                         var indArplAdd = parseInt(lastarpl + 1);
629
+				                     } else { var indArplAdd = 0; }
630
+						     $("#autoReplyTbl").append("<tr><td><input type='text' class='arplAuthor' value='"+ cusrDisplayName +"' disabled></td><td><select id='arpphn-"+ indArplAdd +"' class='arplPhoneNmbr'>"+ numbersListItems +"</select></td><td><div id='arplmode-"+ indArplAdd +"' class='arplMode'><select id='modeselect-"+ indArplAdd +"' class='selectArplMode'><option value='' selected>Select mode</option><option value='daily'>Daily mode</option><option value='vacation'>Vacation mode</option></select><div id='modecont-"+ indArplAdd +"' class='modeContent'></div></div></td><td><textarea id='arpltxt-"+ indArplAdd +"' class='arplText' rows='20' cols='40' placeholder='Enter the auto-reply message here.'></textarea></td><td><img id='rmRow-"+ indArplAdd +"' class='removeRow' src='/" + ctappdir + "/sms_relentless/img/closewnd.svg' title='Remove this row from the database' style='cursor:pointer;margin:9px 8px 0px 18px;'></td><td><input type='submit' id='arplsave-"+ indArplAdd +"' class='saveAutoReply' value='Save' title='Save Row' /></td></tr>");
631
+
632
+				                     selectMode();
633
+				                     saveArplRow();
634
+				                     removeArplRow();
635
+
636
+						     // Check if there is an auto-reply set for the same phone number
637
+						     $("#arpphn-"+ indArplAdd).change(function() {
638
+							 var selectedPhNb = $("#arpphn-"+ indArplAdd).val();
639
+							 var allArplPhNmbrs = $("#autoReplyTbl").find("tr").find(".arplPhoneNmbr");
640
+							 var phNbChck = 0;
641
+							 allArplPhNmbrs.each(function() {
642
+							    var slctphnb = ($(this).val())? $(this).val() : $(this).text();
643
+							    if (selectedPhNb == slctphnb) { phNbChck++; }
644
+							 });
645
+
646
+							 if (phNbChck == 2) {
647
+							     showAlert("There is already an auto-reply set up for this phone number. Please edit its own row, or choose a different phone number.");
648
+							     $(this).val('');
649
+							     return;
650
+							 }
651
+						     });
652
+				                  });
653
+
654
+				  },
655
+				  error: function() {
656
+				                    $("#autoRplPhoneNb").removeClass('icon-loading'); 
657
+				                    showAlert("Error while attempting to get the auto-reply settings! You can check the Nextcloud log to find more details about this issue.");
658
+				  }
659
+			 });
660
+
661
+		     },
662
+		     error: function() {
663
+				  showAlert('Error while getting the settings! You can check the Nextcloud log to find more details about this issue.');
664
+		     }
665
+		  });
666
+
667
+
668
+
669
+		  // Save personal settings for non-admin users
670
+		  $("#save_sms_settings").on("click", function(event) {
671
+
672
+		     if (isadm == 'reguser') {
673
+
674
+			    event.preventDefault();
675
+			    var baseUrlsave = OC.generateUrl('/apps/sms_relentless/user/updatesettings');
676
+
677
+			    var messagesperpageinit = $("#messagesperpage").val();
678
+			    var messagesperpagesec = messagesperpageinit.replace(/[^0-9]/g, '');
679
+			    var messagesperpageproc = 100;
680
+
681
+			    if (messagesperpagesec != '') {
682
+				if (messagesperpagesec > 0 && messagesperpagesec < 4294967296) {
683
+				    messagesperpageproc = messagesperpagesec;
684
+				} else { alert("The field 'Number of messages per page' must contain a number between 1 and 4294967295."); return; }
685
+			    }
686
+
687
+			    var msgcheckintervalinit = $("#msgcheckinterval").val();
688
+			    var msgcheckintervalsec = msgcheckintervalinit.replace(/[^0-9]/g, '');
689
+			    var msgsCheckInterval = 5;
690
+
691
+			    if (msgcheckintervalsec != '') {
692
+				if (msgcheckintervalsec > 0 && msgcheckintervalsec < 86401) {
693
+				    msgsCheckInterval = msgcheckintervalsec;
694
+				} else { alert("The field 'Time interval in seconds before checking if a new message has arrived' must contain a number between 1 and 86400."); return; }
695
+			    }
696
+
697
+			    var getnotify = 0;
698
+
699
+			    if ($("#get_notify").is(':checked')) {
700
+				getnotify = 1;
701
+			    }
702
+
703
+			    var emailaddressinit = $("#notification_email").val();
704
+
705
+			    function validate_email($email) {
706
+				var email_reg = /^([\w-\.]+@([\w-]+\.)+[\w-]{2,4})?$/;
707
+				return email_reg.test($email);
708
+			    }
709
+
710
+			    if (validate_email(emailaddressinit)) {
711
+				 var notifyemail = emailaddressinit;
712
+			    } else {
713
+				 var notifyemail = '';
714
+			    }
715
+
716
+			    var includesmsinemail = 0;
717
+			    if ($("#includesmsinemail").is(':checked')) {
718
+				includesmsinemail = 1;
719
+				if ($("#notification_email").val().trim() == '') {
720
+				    showAlert("Please enter an email address in the field: 'I want to receive a notification to the email address from below ...', or uncheck the checkbox: 'Include the SMS/MMS message in the email notification itself'.");
721
+				    return;
722
+				}
723
+			    }
724
+
725
+			    var showdisplaynm = 0;
726
+			    if ($("#showdisplaynames").is(':checked')) {
727
+				showdisplaynm = 1;
728
+			    }
729
+
730
+			    var adddisplaynm = 0;
731
+			    if ($("#adddisplaynames").is(':checked')) {
732
+				adddisplaynm = 1;
733
+			    }
734
+
735
+			    var datatosave = {
736
+					      userId: userid,
737
+					      telapiUrlRec: $("#telapi_url_rec").val(),
738
+					      telapiUrl: $("#telapi_url").val(),
739
+					      nexapiUrlRec: $("#nexapi_url_rec").val(),
740
+					      nexapiUrl: $("#nexapi_url").val(),
741
+					      twilapiUrlRec: $("#twilapi_url_rec").val(),
742
+					      twilapiUrl: $("#twilapi_url").val(),
743
+					      flowapiUrlRec: $("#flowapi_url_rec").val(),
744
+					      flowapiUrl: $("#flowapi_url").val(),
745
+					      messagesperpage: messagesperpageproc,
746
+		 	                      msgCheckInterval: msgsCheckInterval,
747
+					      getNotify: getnotify,
748
+					      notificationEmail: notifyemail,
749
+					      getsmsinemail: includesmsinemail,
750
+					      showDisplayNames: showdisplaynm,
751
+				              addDisplayNames: adddisplaynm
752
+			    };
753
+
754
+
755
+			    $.ajax({
756
+			       method: 'PUT',
757
+			       url: baseUrlsave + '/' + userid,
758
+			       contentType: 'application/json',
759
+			       data: JSON.stringify(datatosave),
760
+			       success: function() {
761
+				               OC.msg.startAction('#smsr_save_msg', t('sms_relentless', 'Saved'));
762
+			       },
763
+			       error: function() {
764
+				    showAlert('Error while attempting to save the settings! You can check the Nextcloud log to find more details about this issue.');
765
+			       }
766
+			    });
767
+
768
+
769
+		     } else if (isadm == 'admin') {
770
+
771
+			    // Save personal settings for admins
772
+			    event.preventDefault();
773
+			    var baseUrlsaveadm = OC.generateUrl('/apps/sms_relentless/user/updatepersadmnsettings');
774
+
775
+			    var messagesperpageinit = $("#messagesperpage").val();
776
+			    var messagesperpagesec = messagesperpageinit.replace(/[^0-9]/g, '');
777
+			    var messagesperpageproc = 100;
778
+
779
+			    if (messagesperpagesec != '') {
780
+				if (messagesperpagesec > 0 && messagesperpagesec < 4294967296) {
781
+				    messagesperpageproc = messagesperpagesec;
782
+				} else { alert("The field 'Number of messages per page' must contain a number between 1 and 4294967295."); return; }
783
+			    }
784
+
785
+			    var msgcheckintervalinit = $("#msgcheckinterval").val();
786
+			    var msgcheckintervalsec = msgcheckintervalinit.replace(/[^0-9]/g, '');
787
+			    var msgsCheckInterval = 5;
788
+
789
+			    if (msgcheckintervalsec != '') {
790
+				if (msgcheckintervalsec > 0 && msgcheckintervalsec < 86401) {
791
+				    msgsCheckInterval = msgcheckintervalsec;
792
+				} else { alert("The field 'Time interval in seconds before checking if a new message has arrived' must contain a number between 1 and 86400."); return; }
793
+			    }
794
+
795
+			    var getnotify = 0;
796
+
797
+			    if ($("#get_notify").is(':checked')) {
798
+				getnotify = 1;
799
+			    }
800
+
801
+			    var emailaddressinit = $("#notification_email").val();
802
+
803
+			    function validate_email($email) {
804
+				var email_reg = /^([\w-\.]+@([\w-]+\.)+[\w-]{2,4})?$/;
805
+				return email_reg.test($email);
806
+			    }
807
+
808
+			    if (validate_email(emailaddressinit)) {
809
+				 var notifyemail = emailaddressinit;
810
+			    } else {
811
+				 var notifyemail = '';
812
+			    }
813
+
814
+			    var includesmsinemail = 0;
815
+			    if ($("#includesmsinemail").is(':checked')) {
816
+				includesmsinemail = 1;
817
+				if ($("#notification_email").val().trim() == '') {
818
+				    showAlert("Please enter an email address in the field: 'I want to receive a notification to the email address from below ...', or uncheck the checkbox: 'Include the SMS/MMS message in the email notification itself'.");
819
+				    return;
820
+				}
821
+			    }
822
+
823
+			    var showdisplaynm = 0;
824
+			    if ($("#showdisplaynames").is(':checked')) {
825
+				showdisplaynm = 1;
826
+			    }
827
+
828
+			    var adddisplaynm = 0;
829
+			    if ($("#adddisplaynames").is(':checked')) {
830
+				adddisplaynm = 1;
831
+			    }
832
+
833
+			    var datatosave = {
834
+					      userId: userid,
835
+					      messagesperpage: messagesperpageproc,
836
+					      msgCheckInterval: msgsCheckInterval,
837
+					      getNotify: getnotify,
838
+					      notificationEmail: notifyemail,
839
+					      getsmsinemail: includesmsinemail,
840
+					      showDisplayNames: showdisplaynm,
841
+				              addDisplayNames: adddisplaynm
842
+			    };
843
+
844
+
845
+			    $.ajax({
846
+			       method: 'PUT',
847
+			       url: baseUrlsaveadm + '/' + userid,
848
+			       contentType: 'application/json',
849
+			       data: JSON.stringify(datatosave),
850
+			       success: function() {
851
+				               OC.msg.startAction('#smsr_save_msg', t('sms_relentless', 'Saved'));
852
+			       },
853
+			       error: function() {
854
+				    showAlert('Error while attempting to save the settings! You can check the Nextcloud log to find more details about this issue.');
855
+			       }
856
+			    });
857
+
858
+		     }
859
+		  });
860
+
861
+		  function showAlert(alertText) {
862
+
863
+		     let alertwnd = "<div id='alertMessage'>";
864
+		     alertwnd += "<a id='closeAlertWnd' title='Close this window'></a>";
865
+		     alertwnd += "<div id='alertTextWrap'>"+ alertText +"</div>";
866
+		     alertwnd += "<input type='submit' id='alertOk' value='OK'>";
867
+		     alertwnd += "</div>";
868
+
869
+		     $("#content").append("<div id='alertMsgOverlay'></div>");
870
+		     $("#content").append(alertwnd);
871
+
872
+		     let topDist = parseInt((window.innerHeight / 2).toFixed(2) - 152) +"px";
873
+		     let leftDist = parseInt((window.innerWidth / 2).toFixed(2) - 150) +"px";
874
+		     $("#alertMessage").css({ "top" : topDist, "left" : leftDist });
875
+
876
+		     $("#closeAlertWnd").click(function() { $("#alertMsgOverlay").remove(); $("#alertMessage").remove(); });
877
+		     $("#alertMsgOverlay").click(function() { $("#alertMsgOverlay").remove(); $("#alertMessage").remove(); });
878
+		     $("#alertOk").click(function() { $("#alertMsgOverlay").remove(); $("#alertMessage").remove(); });
879
+		  }
880
+
881
+		  function confirmAlert(alertText) {
882
+
883
+		     $("#alertMsgOverlay").remove();
884
+		     $("#alertConfMessage").remove();
885
+
886
+		     let alertwndcf = "<div id='alertConfMessage'>";
887
+		     alertwndcf += "<a id='closeAlertWndcf' title='Close this window'></a>";
888
+		     alertwndcf += "<div id='alertTextWrap'>"+ alertText +"</div>";
889
+		     alertwndcf += "<div id='cancelOkWrap'><input type='submit' id='confirmCancel' value='Cancel'>";
890
+		     alertwndcf += "<input type='submit' id='confirmOk' value='OK'></div>";
891
+		     alertwndcf += "</div>";
892
+
893
+		     $("#content").append("<div id='alertMsgOverlay'></div>");
894
+		     $("#content").append(alertwndcf);
895
+
896
+		     let topDist = parseInt((window.innerHeight / 2).toFixed(2) - 152) +"px";
897
+		     let leftDist = parseInt((window.innerWidth / 2).toFixed(2) - 150) +"px";
898
+		     $("#alertConfMessage").css({ "top" : topDist, "left" : leftDist });
899
+
900
+		     $("#closeAlertWndcf").click(function() { $("#alertMsgOverlay").remove(); $("#alertConfMessage").remove(); });
901
+		     $("#alertMsgOverlay").click(function() { $("#alertMsgOverlay").remove(); $("#alertConfMessage").remove(); });
902
+		  }
903
+
904
+
905
+     },
906
+     error: function(appdirfdb) {
907
+                alert("An error occurred while getting the app's directory. You can check the Nextcloud log to find more details about this issue.");
908
+     }
909
+   });
910
+
911
+});
0 912
new file mode 100644
... ...
@@ -0,0 +1,5048 @@
1
+/**
2
+ * @copyright 2021 Double Bastion LLC <www.doublebastion.com>
3
+ *
4
+ * @author Double Bastion LLC
5
+ *
6
+ * @license GNU AGPL version 3 or any later version
7
+ *
8
+ * This program is free software; you can redistribute it and/or
9
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
10
+ * License as published by the Free Software Foundation; either
11
+ * version 3 of the License, or any later version.
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
17
+ *
18
+ * You should have received a copy of the GNU Affero General Public
19
+ * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
+ *
21
+ */
22
+
23
+$(document).ready(function() {
24
+
25
+  var userid = "<?php p($userId); ?>";
26
+  var parseddata = null;
27
+  var sentparseddata = null;
28
+  var groupedparsed = null;
29
+  var messagesperpage = 100;
30
+  var newMsgInterval = 5000;
31
+  var newMsgRcd = 0;
32
+  var intervalRfrSent = 0;
33
+  var intervalNmfr = null;
34
+  var ctappdir = 'apps';
35
+
36
+  // Get the app's directory
37
+  var getappdirurl = OC.generateUrl('/apps/sms_relentless/user/getappdirectory');
38
+
39
+  $.ajax({
40
+     method: 'GET',
41
+     url: getappdirurl + '/' + userid,
42
+     contentType: 'application/json',
43
+     success: function(appdirfdb) {
44
+                ctappdir = appdirfdb;
45
+     },
46
+     error: function(appdirfdb) {
47
+                alert("An error occurred while getting the app's directory. You can check the Nextcloud log to find more details about this issue.");
48
+     }
49
+  });
50
+
51
+  // Get the number of messages per page and the time interval for checking for new received messages, from the database
52
+  var getNoPerPageUrl = OC.generateUrl("/apps/sms_relentless/user/getmsgsperpagenewmsg");
53
+
54
+  $.ajax({
55
+        url: getNoPerPageUrl + '/' + userid,
56
+        method: 'GET',
57
+        success: function(mesperpagedb) {
58
+                 if (mesperpagedb.msgsperpage) { messagesperpage = mesperpagedb.msgsperpage; }
59
+                 if (mesperpagedb.newmsgcheck) { newMsgInterval = mesperpagedb.newmsgcheck * 1000; }
60
+        },
61
+        error: function(mesperpagedb) {
62
+                 showAlert("Error while getting the number of messages per page. You can check the Nextcloud log to find more details about this issue!");
63
+        }
64
+  });
65
+
66
+  // Get the 'new received message' indicator from the database
67
+  function checkIfNewMessage() {
68
+
69
+        var getNewMsgInd = OC.generateUrl("/apps/sms_relentless/user/getnewmsgindicator");
70
+
71
+        $.ajax({
72
+              url: getNewMsgInd + '/' + userid,
73
+              method: 'GET',
74
+              success: function(newmsgdb) {
75
+                       newMsgRcd = newmsgdb;
76
+                       if (newMsgRcd == 1) { 
77
+                           $('#smstables').empty();
78
+                           if ($("#listAllMsgsFromTo").is(":visible")) { setTimeout(function() { $("#refreshMsgsConvtf").click(); }, 500); }
79
+                           if ($("#listAllMsgsConv").is(":visible")) { setTimeout(function() { $("#refreshMsgsConv").click(); }, 500); }
80
+                           $("#receivedsmstableshow").click();
81
+                       }
82
+              },
83
+              error: function(newmsgdb) {
84
+                           // showAlert("Error while getting the 'new received message' indicator. You can check the Nextcloud log to find more details about this issue!");
85
+              }
86
+        });
87
+  }
88
+
89
+
90
+  // List received messages
91
+  $("#receivedsmstableshow").on("click", function(event) {
92
+
93
+     $('#smstables').empty();
94
+     clearInterval(intervalNmfr);
95
+
96
+     var getReceivedUrl = OC.generateUrl("/apps/sms_relentless/user/getreceivedtable");
97
+
98
+     $('#smstables').addClass('icon-loading');
99
+
100
+     $.ajax({
101
+          url: getReceivedUrl + '/' + userid,
102
+          method: 'GET',
103
+          contentType: 'application/json',
104
+          success: function(datafdb) {
105
+
106
+                var parseddata = datafdb.datarows;
107
+
108
+                $('#smstables').append("<div id='toptablerec'><div class='topbuttonandpage'><span id='recarrow' title='Show/Hide filters and Delete button'></span></div><div id='paginationrec' class='recpages'>Pages </div></div>");
109
+                $('#smstables').append("<table id='recSmsTable'></table>");
110
+
111
+                $('#recSmsTable').append("<tr id='recfiltersrow'><td class='selectalldvfilter'><button id='clearrecfilters' title='Clear all filters.'></button><button id='deleterecrows' title='Permanently delete the selected row(s) from below from the database.'></button></td><td class='selectalldvfilter'><input type='text' id='dbidtextrec' class='indivfilterrec' title='Enter a database ID number to apply the filter.'><input type='submit' id='databaseidfilter' class='filterbuttonsrec' value='' title='Filter rows by the specified database ID.' /></td><td class='selectalldvfilter'><input type='text' id='useridtextrec' class='indivfilterrec' title='Enter a Nextcloud username to apply the filter.' /><input type='submit' id='useridfilter' class='filterbuttonsrec' value='' title='Filter rows by the specified username.' /></td><td class='selectalldvfilter'><input type='text' id='messageidtextrec' class='indivfilterrec' title='Enter a fragment from a message ID to apply the filter.'  /><input type='submit' id='messageidfilter' class='filterbuttonsrec' value='' title='Filter rows by the specified string.' /></td><td class='selectalldvfilter'><input type='text' id='datetextrec' class='indivfilterrec' title='Enter a fragment of a date to apply the filter.'/><input type='submit' id='datefilter' class='filterbuttonsrec' value='' title='Filter rows by the specified string.' /></td><td class='selectalldvfilter'><input type='text' id='fromtextrec' class='indivfilterrec' title='Enter a fragment of a sender&#146s phone number or alphanumeric sender ID, to apply the filter.' /><input type='submit' id='fromfilter' class='filterbuttonsrec' value='' title='Filter rows by the specified string.' /></td><td class='selectalldvfilter'><input type='text' id='totextrec' class='indivfilterrec' value='' title='Enter a fragment of a recipient&#146s phone number to apply the filter.'  /><input type='submit' id='tofilter' class='filterbuttonsrec' value='' title='Filter rows by the specified string.' /></td><td class='selectalldvfilter'><input type='text' id='messagetextrec' class='indivfilterrec' title='Enter a fragment of a message to apply the filter.' /><input type='submit' id='messagefilter' class='filterbuttonsrec' value='' title='Filter rows by the specified string.'/></td></tr>");
112
+                $('#recSmsTable').append("<tr class='receivedrows' id='recheaderrow'><th id='selectalldv' class='selectsmsdv'><input type='checkbox' id='selectAllChckbx' class ='indivchckbx' title='Select all rows.' /></th><th title='The database ID of each message.'>ID</th><th>User ID</th><th>Message ID</th><th>Date</th><th>From</th><th>To</th><th>Received Message</th></tr>");
113
+
114
+                $('#recfiltersrow').hide();
115
+
116
+                if (datafdb.showdispnm == 1) {
117
+
118
+                    for (var i = 0; i < parseddata.length; i++) {
119
+
120
+                         if (parseddata[i].author_displayname) {
121
+                             var procrcmessage = "<span class='messageAuthorName'>"+ parseddata[i].author_displayname + ":</span>" + parseddata[i].message +"<div id='showMsgConv-"+ i +"' class='lstMsgConv'><img class='lstMsgConvImg' src='/" + ctappdir + "/sms_relentless/img/reply.svg' title='Show all the messages exchanged between the current 2 phone numbers.'></div>";
122
+                         } else {
123
+                             var procrcmessage = parseddata[i].message +"<div id='showMsgConv-"+ i +"' class='lstMsgConv'><img class='lstMsgConvImg' src='/" + ctappdir + "/sms_relentless/img/reply.svg' title='Show all the messages exchanged between the current 2 phone numbers.'></div>";
124
+                         }
125
+
126
+                         if (parseddata[i].internal_sender == 0) {
127
+                             var procrecFrom = "<div id='frmNmbr-"+ i +"'><div id='addDispName-"+ i +"' style='display:block;margin-right:5px;'><img class='addNameToPhNb' src='/" + ctappdir + "/sms_relentless/img/user-grey.svg' title='Associate a Display Name with this phone number'></div>"+ parseddata[i].from +"<div id='showMsgFrom-"+ i +"' class='listToFromMsgs'><img class='lstMsgToFromImg' src='/" + ctappdir + "/sms_relentless/img/list.svg' title='Show all the messages sent/received to/from this phone number, that I am allowed to see.'></div></div>";
128
+                         } else {
129
+                             var procrecFrom = "<div id='frmNmbr-"+ i +"'>"+ parseddata[i].from +"<div id='showMsgFrom-"+ i +"' class='listToFromMsgs'><img class='lstMsgToFromImg' src = '/" + ctappdir + "/sms_relentless/img/list.svg' title='Show all the messages sent/received to/from this phone number, that I am allowed to see.'></div></div>";
130
+                         }
131
+
132
+                         var procrecTo = "<div id='toNmbr-"+ i +"'>"+ parseddata[i].to +"<div id='showMsgTo-"+ i +"' class='listToFromMsgs'><img class='lstMsgToFromImg' src = '/" + ctappdir + "/sms_relentless/img/list.svg' title='Show all the messages sent/received to/from this phone number, that I am allowed to see.'></div></div>";
133
+
134
+                         $("#recSmsTable").append("<tr id='singlerow_"+ i +"' class='receivedrowsbody'><td class='selectsmsdv'><input type='checkbox' id='selectspec_"+ i +"' class='indivchckbx' /></td><td class='dbidcolumnrec'>"+ parseddata[i].id +"</td><td class='useridcolrec'>"+ parseddata[i].user_id +"</td><td class='messageidcolrec'>"+ parseddata[i].message_id +"</td><td class='datecolrec'>"+ parseddata[i].date +"</td><td class='fromcolumnrec'>"+ procrecFrom +"</td><td class='tocolrec'>"+ procrecTo +"</td><td class='messagecolumnrec'>"+ procrcmessage +"</td></tr>");
135
+                    }
136
+
137
+                } else {
138
+
139
+                    for (var i = 0; i < parseddata.length; i++) {
140
+
141
+                         var procrcmessage = parseddata[i].message +"<div id='showMsgConv-"+ i +"' class='lstMsgConv'><img class='lstMsgConvImg' src='/" + ctappdir + "/sms_relentless/img/reply.svg' title='Show all the messages exchanged between the current 2 phone numbers.'></div>";
142
+
143
+                         if (parseddata[i].internal_sender == 0) {
144
+                             var procrecFrom = "<div id='frmNmbr-"+ i +"'><div id='addDispName-"+ i +"' style='display:block;margin-right:5px;'><img class='addNameToPhNb' src='/" + ctappdir + "/sms_relentless/img/user-grey.svg' title='Associate a Display Name with this phone number'></div>"+ parseddata[i].from +"<div id='showMsgFrom-"+ i +"' class='listToFromMsgs'><img class='lstMsgToFromImg' src='/" + ctappdir + "/sms_relentless/img/list.svg' title='Show all the messages sent/received to/from this phone number, that I am allowed to see.'></div></div>";
145
+                         } else {
146
+                             var procrecFrom = "<div id='frmNmbr-"+ i +"'>"+ parseddata[i].from +"<div id='showMsgFrom-"+ i +"' class='listToFromMsgs'><img class='lstMsgToFromImg' src = '/" + ctappdir + "/sms_relentless/img/list.svg' title='Show all the messages sent/received to/from this phone number, that I am allowed to see.'></div></div>";
147
+                         }
148
+
149
+                         var procrecTo = "<div id='toNmbr-"+ i +"'>"+ parseddata[i].to +"<div id='showMsgTo-"+ i +"' class='listToFromMsgs'><img class='lstMsgToFromImg' src = '/" + ctappdir + "/sms_relentless/img/list.svg' title='Show all the messages sent/received to/from this phone number, that I am allowed to see.'></div></div>";
150
+
151
+                         $("#recSmsTable").append("<tr id='singlerow_"+ i +"' class='receivedrowsbody'><td class='selectsmsdv'><input type='checkbox' id='selectspec_"+ i +"' class='indivchckbx' /></td><td class='dbidcolumnrec'>"+ parseddata[i].id +"</td><td class='useridcolrec'>"+ parseddata[i].user_id +"</td><td class='messageidcolrec'>"+ parseddata[i].message_id +"</td><td class='datecolrec'>"+ parseddata[i].date +"</td><td class='fromcolumnrec'>"+ procrecFrom +"</td><td class='tocolrec'>"+ procrecTo +"</td><td class='messagecolumnrec'>"+ procrcmessage +"</td></tr>");
152
+                    }
153
+                }
154
+
155
+                $('#smstables').append("<div id='totalrecmessages'>Total displayed messages: " + parseddata.length + "</div>");
156
+
157
+                $('#smstables').removeClass('icon-loading');
158
+                $('#recarrow').removeClass('arrowUpCl');
159
+                $('#recarrow').addClass('arrowDownCl');
160
+
161
+                // Show the pop-up window that lists all the messages exchanged between the current 2 phone numbers
162
+                function showRecMsgPerConv(phNumberFrom, phNumberTo) {
163
+
164
+                   let allfrmtomsg = "<div id='listAllMsgsConv'>";
165
+                   allfrmtomsg += "<div id='draglstMsgmWindow'><img src='/" + ctappdir + "/sms_relentless/img/dots.svg'></div>";
166
+                   allfrmtomsg += "<a id='closeFrmMsgWindow' title='Close this window'></a>";
167
+                   allfrmtomsg += "<div class='showByNmbrTitle'>Messages exchanged between <span style='color:#04957b'>"+ phNumberFrom +"</span> and <span style='color:#04957b'>"+ phNumberTo +"</span></div>";
168
+                   allfrmtomsg += "<div id='frmMsgLstWrap'>";
169
+                   allfrmtomsg += "<table id='frmMsgLstTbl'>";
170
+                   allfrmtomsg += "<tr class='groupedrowsbody'><td><div id='grpdbynamelst' class='groupedLstNamespn'></div></td><td><div id='loadMoreMsgs' title='Click to load older messages.'>Load more messages</div><div id='loadMoreMsgsusr' title='Click to load older messages.'>Load more messages</div><div id='msgListRowCell' class='groupedLstMsgspn'></div><div id='refreshMsgsWrap'><div id='refreshMsgsConv' title='Refresh list of messages'></div></div><div id='arrowupWrap'><div id='upArrowSmall' title='Scroll to the top'></div></div></td></tr>";
171
+                   allfrmtomsg += "</table></div>";
172
+                   allfrmtomsg += "<div id='sendMsgReply'><table id='sendMsgConv'><tr><td><div id='fromPhoneNmbrConv'>From: <select id='selectFromNbConv'></select></div><div id='toPhoneNmbrConv'>To: <span id='toNmbrConv' style='color:#04957b'>"+ phNumberFrom +"</span></div></td></tr>";
173
+                   allfrmtomsg += "<tr><td><textarea id='sendMsgConvText' placeholder='Enter a message here, then press Send SMS'></textarea></td></tr></table>";
174
+                   allfrmtomsg += "<div id='sendMsgConvBtn'>Send SMS</div></div>";
175
+                   allfrmtomsg += "<div style='display:block;width:100%;height:14px;'><img id='expandWindowRpl' src='/" + ctappdir + "/sms_relentless/img/arrowDown.svg' title='Expand to send a reply'></div>";
176
+                   allfrmtomsg += "<div id='draglstMsgmWindowsc'><img src='/" + ctappdir + "/sms_relentless/img/dots.svg' style='padding:4px;vertical-align:top;'></div>";
177
+                   allfrmtomsg += "</div>";
178
+
179
+                   $("#content").append("<div id='recTblOverlay'></div>");
180
+                   $("#content").append(allfrmtomsg);
181
+
182
+                   let topDist = parseInt((window.innerHeight / 2).toFixed(2) - 340) +"px";
183
+                   let leftDist = parseInt((window.innerWidth / 2).toFixed(2) - 300) +"px";
184
+                   $("#listAllMsgsConv").css({ "top" : topDist, "left" : leftDist });
185
+
186
+                   $("#closeFrmMsgWindow").click(function() { $("#listAllMsgsConv").remove(); $("#recTblOverlay").remove(); });
187
+                   $("#recTblOverlay").click(function() { $("#listAllMsgsConv").remove(); $("#recTblOverlay").remove(); });
188
+
189
+
190
+	           // Expand the window when clicking on the arrow, to be able to send a reply message
191
+                   $("#expandWindowRpl").unbind("click");
192
+	           $("#expandWindowRpl").click(function() {
193
+
194
+	              if ($(this).attr('src') == '/' + ctappdir + '/sms_relentless/img/arrowDown.svg') {
195
+                          $("#sendMsgReply").css("display", "block");
196
+                          $("#listAllMsgsConv").css("height", "618px");
197
+	                  $(this).attr('src', '/' + ctappdir + '/sms_relentless/img/arrowUp.svg');
198
+                          $(this).attr('title', 'Collapse');
199
+
200
+	              } else {
201
+
202
+                          $("#sendMsgReply").css("display", "none");
203
+                          $("#listAllMsgsConv").css("height", "490px");
204
+                          $(this).attr('src', '/' + ctappdir + '/sms_relentless/img/arrowDown.svg');
205
+                          $(this).attr('title', 'Expand to send a reply');
206
+	              }
207
+	           });
208
+
209
+
210
+                   // Send a message from the 'conversation' window
211
+                   $("#sendMsgConvBtn").click(function() {
212
+
213
+                      $("#sendMsgConv,#sendMsgConvBtn").addClass('icon-loading');
214
+                      var msgToSend = $("#sendMsgConvText").val();
215
+                      var selectedid = $("#selectFromNbConv").val();
216
+                      var toNumber = $("#toNmbrConv").text();
217
+                      var receiversNumbers = [toNumber];
218
+
219
+		      if (selectedid != '') { 
220
+
221
+			  var sendersplit = selectedid.split(":");
222
+			  var providercap = sendersplit[0];
223
+			  var provsec = sendersplit[1];
224
+
225
+			  if (/[a-zA-Z]/.test(provsec)) {
226
+			      var alphanumcheck = true;
227
+			  } else { var alphanumcheck = false; }
228
+
229
+			  if (providercap == 'Tx' && alphanumcheck == false) {  
230
+			      var senderproc = selectedid.replace(/[^0-9]/g, "");
231
+			      var selectedsender = "+" + senderproc;
232
+			      var providerUsed = "telnyx";
233
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmstel");
234
+			  } else if (providercap == 'Pl' && alphanumcheck == false) {
235
+			      var selectedsender = selectedid.replace(/[^0-9]/g, "");
236
+			      var providerUsed = "plivo";
237
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmsnex");
238
+			  } else if (providercap == 'Tw' && alphanumcheck == false) {  
239
+			      var senderproc = selectedid.replace(/[^0-9]/g, "");
240
+			      var selectedsender = "+" + senderproc;
241
+			      var providerUsed = "twilio";
242
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmstwil");
243
+			  } else if (providercap == 'Fl' && alphanumcheck == false) {  
244
+			      var senderproc = selectedid.replace(/[^0-9]/g, "");
245
+			      var selectedsender = "+" + senderproc;
246
+			      var providerUsed = "flowroute";
247
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmsflow");
248
+			  } else if (providercap == 'Tx' && alphanumcheck == true) {
249
+			      var selectedsender = provsec;
250
+			      var providerUsed = "telnyx";
251
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmstel");
252
+			  } else if (providercap == 'Pl' && alphanumcheck == true) {
253
+			      var selectedsender = provsec;
254
+			      var providerUsed = "plivo";
255
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmsnex");
256
+			  } else if (providercap == 'Tw' && alphanumcheck == true) {
257
+			      var selectedsender = provsec;
258
+			      var providerUsed = "twilio";
259
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmstwil");
260
+			  } else if (providercap == 'Fl' && alphanumcheck == true) {
261
+			      var selectedsender = provsec;
262
+			      var providerUsed = "flowroute";
263
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmsflow");
264
+			  }
265
+
266
+                          var uploadedtomms = [];
267
+
268
+	                  if (msgToSend != '') {
269
+
270
+				  $.ajax({
271
+				     url: relbaseUrl + '/' + userid,
272
+				     type: "POST",
273
+				     data: {
274
+				           receiversPhoneNbs: receiversNumbers,
275
+				           fromsender: selectedsender,
276
+				           waitinterval: 1000,
277
+				           sentsmstext: msgToSend,
278
+				           ismms: 0,
279
+				           mmsfiles: uploadedtomms
280
+				         },
281
+				     success: function(displayname) {
282
+
283
+                                           var tzdate = new Date();
284
+                                           var presDatest = new Date(tzdate.getTime() - (tzdate.getTimezoneOffset() * 60000)).toJSON();
285
+                                           var presDatedb = presDatest.split(".")[0];
286
+                                           var presDatesc = presDatedb.split("T");
287
+                                           var presDate = presDatesc[0] +" "+ presDatesc[1];
288
+                                           var sentMessageStatus = '';
289
+
290
+                                           if (displayname) {
291
+                                               var msgToSendproc = "<span class='msgAuthorNameGrp'>"+ displayname + ":</span>" + msgToSend; 
292
+                                           } else { var msgToSendproc = msgToSend; }
293
+
294
+                                           $("#msgListRowCell").append("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent to current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ selectedsender +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ receiversNumbers[0] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ msgToSendproc +"</div><div style='display:inline-block;margin:6px 6px 0px 4px;font-size:12.5px;color:#353535;'>"+ presDate +"</div><div class='sentMssgStatus'>"+ sentMessageStatus +"</div></div>");
295
+
296
+                                           // Scroll down to the bottom of the window
297
+                                           $("#frmMsgLstWrap").animate({scrollTop:$("#frmMsgLstTbl").prop("scrollHeight")},200);
298
+
299
+                                           $("#sendMsgConv,#sendMsgConvBtn").removeClass('icon-loading');
300
+				     },
301
+				     error: function() {
302
+                                           showAlert("Error while sending the message. You can check your Nextcloud log to find out more about this issue.");
303
+				           $("#sendMsgConv,#sendMsgConvBtn").removeClass('icon-loading');
304
+				     }
305
+				  });
306
+			  } else {
307
+                                  showAlert("Please enter a message in the text box!");
308
+				  $("#sendMsgConv,#sendMsgConvBtn").removeClass('icon-loading');
309
+			  }
310
+		      } else {
311
+                              showAlert("Please choose a Sender ID from the 'From' drop-down list!");
312
+			      $("#sendMsgConv,#sendMsgConvBtn").removeClass('icon-loading');
313
+		      }
314
+
315
+                   });
316
+
317
+
318
+	           // Make the window draggable
319
+	           function makeMgrWndDraggable(e) {
320
+
321
+			   window.pmdragging = {};
322
+			   pmdragging.pageX0 = e.pageX;
323
+			   pmdragging.pageY0 = e.pageY;
324
+			   pmdragging.elem = $("#listAllMsgsConv");
325
+			   pmdragging.offset0 = $("#listAllMsgsConv").offset();
326
+
327
+			   function handle_dragging(e) {
328
+			       let left = pmdragging.offset0.left + (e.pageX - pmdragging.pageX0);
329
+			       let top = pmdragging.offset0.top + (e.pageY - pmdragging.pageY0);
330
+			       $(pmdragging.elem).offset({top: top, left: left});
331
+			   }
332
+
333
+			   function handle_mouseup(e) {
334
+			       $('body').off('mousemove', handle_dragging).off('mouseup', handle_mouseup);
335
+			   }
336
+
337
+			   $('body').on('mouseup', handle_mouseup).on('mousemove', handle_dragging);
338
+	           }
339
+	           $("#draglstMsgmWindow").mousedown(makeMgrWndDraggable);
340
+	           $("#draglstMsgmWindowsc").mousedown(makeMgrWndDraggable);
341
+
342
+
343
+                   // Append the available phone numbers to the From drop-down list
344
+                   var availPhoneNmbrs = [];
345
+                   $("#currentsmsnmbrs .optselectsmsnb").each(function() {
346
+                      var crtphnmbr = $(this).attr("value");
347
+                      if (crtphnmbr != "") { availPhoneNmbrs.push(crtphnmbr); }
348
+                   });
349
+
350
+                   if (availPhoneNmbrs.length > 0) {
351
+                       var avphopt = "";
352
+                       for (let d = 0; d < availPhoneNmbrs.length; d++) {
353
+                            if (availPhoneNmbrs[d].indexOf(phNumberTo) === -1) {
354
+                                avphopt += "<option value='"+ availPhoneNmbrs[d] +"'>"+ availPhoneNmbrs[d] +"</option>";
355
+                            } else {
356
+                                avphopt += "<option value='"+ availPhoneNmbrs[d] +"' selected>"+ availPhoneNmbrs[d] +"</option>";
357
+                            }
358
+                       }
359
+                       $("#selectFromNbConv").append(avphopt);
360
+
361
+                   } else { $("#selectFromNbConv").append("<option value='' selected>No IDs</option>"); }
362
+
363
+
364
+                   // Get the sent/received messages for the current phone numbers, from the database
365
+                   function getMsgsForNumbers(phNumberFrom, phNumberTo) {
366
+
367
+			   let getGrpConvUrl = OC.generateUrl("/apps/sms_relentless/user/getgroupedforreply");
368
+
369
+			   $('#listAllMsgsConv').addClass('icon-loading');
370
+
371
+			   let totalPhNmbrs = 0;
372
+
373
+			   $.ajax({
374
+				  method: 'POST',
375
+				  url: getGrpConvUrl + '/' + userid,
376
+				  contentType: 'application/json',
377
+		                  data: JSON.stringify({ phoneNmbrFrom: phNumberFrom, phoneNmbrTo: phNumberTo }),
378
+				  success: function(groupedperconv) {
379
+
380
+					     $('#listAllMsgsConv').removeClass('icon-loading');
381
+
382
+					     let fromtoNmbrsData = [];
383
+
384
+					     for (let i = 0; i < groupedperconv.length; i++) {
385
+
386
+						     if (groupedperconv[i].author_displayname) {
387
+							 var authordnm = groupedperconv[i].author_displayname;
388
+						     } else { 
389
+							 var authordnm = '';
390
+						     }
391
+
392
+						     var sentfromnmbrarr = groupedperconv[i].from.split(": ");
393
+						     if (sentfromnmbrarr[1]) {
394
+					                 var groupednbfrom = sentfromnmbrarr[1];
395
+                                                     } else {
396
+					                 var groupednbfrom = sentfromnmbrarr[0];
397
+                                                     }
398
+
399
+						     var modmessagerec = '';
400
+						     if (groupedperconv[i].author_displayname) {
401
+							 modmessagerec = "<span class='msgAuthorNameGrp'>"+ groupedperconv[i].author_displayname + ":</span>" + groupedperconv[i].message;
402
+						     } else {
403
+					                 modmessagerec = groupedperconv[i].message;
404
+		                                     }
405
+
406
+						     if (groupedperconv[i].to.indexOf(": ") > -1) {
407
+						         var groupednmbrtopre = groupedperconv[i].to.split(": ");
408
+						         var groupednmbrto = groupednmbrtopre[1];
409
+						     } else { 
410
+						         var groupednmbrto = groupedperconv[i].to;
411
+						     }
412
+
413
+						     fromtoNmbrsData.push({
414
+						               'author_displayname': authordnm,
415
+						               'from': groupednbfrom,
416
+						               'to': groupednmbrto,
417
+						               'message': modmessagerec,
418
+						               'date': groupedperconv[i].date,
419
+						               'status': groupedperconv[i].deliveryreceipt,
420
+						               'table': groupedperconv[i].table
421
+						     });
422
+					     }
423
+
424
+
425
+					     // Remove the duplicates
426
+					     let noDupMsgData = [];
427
+					     $.each(fromtoNmbrsData, function(i, e) {
428
+						    let matchingData = $.grep(noDupMsgData, function(item) {
429
+						            return item.from == e.from && item.to == e.to && item.message == e.message && item.table == 'received' && e.table == 'sent';
430
+						    });
431
+						    if (matchingData.length === 0) {
432
+							noDupMsgData.push(e);
433
+						    }
434
+					     });
435
+
436
+					     let messagesPerNmbr = {};
437
+					     let msgsNamesPerNmbr = {};
438
+					     let msgsNmbrsNames = {};
439
+
440
+					     let displayNamesarr = [];
441
+					     let convData = [];
442
+
443
+					     for (let n = 0; n < noDupMsgData.length; n++) {
444
+
445
+					          if (noDupMsgData[n]['from'] == phNumberFrom && noDupMsgData[n]['table'] == 'sent') {
446
+
447
+					              convData.push({
448
+					                             'author_displayname': noDupMsgData[n]['author_displayname'],
449
+					                             'message': noDupMsgData[n]['message'],
450
+					                             'from': noDupMsgData[n]['from'],
451
+					                             'to': noDupMsgData[n]['to'],
452
+					                             'date': noDupMsgData[n]['date'],
453
+					                             'direction': 'sent_from',
454
+					                             'status': noDupMsgData[n]['status'],
455
+					                             'table': noDupMsgData[n]['table']
456
+					              });
457
+
458
+					          } else if (noDupMsgData[n]['to'] == phNumberFrom && noDupMsgData[n]['table'] == 'sent') {
459
+
460
+					              convData.push({
461
+					                             'author_displayname': noDupMsgData[n]['author_displayname'],
462
+					                             'message': noDupMsgData[n]['message'],
463
+					                             'from': noDupMsgData[n]['from'],
464
+					                             'to': noDupMsgData[n]['to'],
465
+					                             'date': noDupMsgData[n]['date'],
466
+					                             'direction': 'sent_to',
467
+					                             'status': noDupMsgData[n]['status'],
468
+					                             'table': noDupMsgData[n]['table']
469
+					              });
470
+
471
+
472
+					          } else if (noDupMsgData[n]['from'] == phNumberFrom && noDupMsgData[n]['table'] == 'received') {
473
+
474
+					              convData.push({
475
+					                             'author_displayname': noDupMsgData[n]['author_displayname'],
476
+					                             'message': noDupMsgData[n]['message'],
477
+					                             'from': noDupMsgData[n]['from'],
478
+					                             'to': noDupMsgData[n]['to'],
479
+					                             'date': noDupMsgData[n]['date'],
480
+					                             'direction': 'received_from',
481
+					                             'status': noDupMsgData[n]['status'],
482
+					                             'table': noDupMsgData[n]['table']
483
+					              });
484
+
485
+					          } else if (noDupMsgData[n]['to'] == phNumberFrom && noDupMsgData[n]['table'] == 'received') {
486
+
487
+					              convData.push({
488
+					                             'author_displayname': noDupMsgData[n]['author_displayname'],
489
+					                             'message': noDupMsgData[n]['message'],
490
+					                             'from': noDupMsgData[n]['from'],
491
+					                             'to': noDupMsgData[n]['to'],
492
+					                             'date': noDupMsgData[n]['date'],
493
+					                             'direction': 'received_on',
494
+					                             'status': noDupMsgData[n]['status'],
495
+					                             'table': noDupMsgData[n]['table']
496
+					              });
497
+					          }
498
+					     }
499
+
500
+					     // Sort messages by date
501
+					     convData.sort(function(a, b) {
502
+						let c = new Date(a.date);
503
+						let d = new Date(b.date);
504
+						return c-d;
505
+					     });
506
+		                             convData.reverse();
507
+
508
+					     // Collect the display names of the users that sent messages from the current number
509
+					     let selectedNames = [];
510
+					     let displayNames = '';
511
+					     for (let v = 0; v < convData.length; v++) {
512
+					          if (selectedNames.indexOf(convData[v]['author_displayname']) == -1) { 
513
+					              selectedNames.push(convData[v]['author_displayname']);
514
+					              displayNames += "<div id='diplNm_"+ phNumberFrom +"_"+ v +"' class='dispNameList' name='"+ convData[v]['author_displayname'] +"'>"+ convData[v]['author_displayname'] +"</div>";
515
+					          }
516
+					     }
517
+					     displayNames += "<div id='diplNmAllMsg' class='dispNameListAll' title='Show all the messages for this number.'>"+ phNumberFrom +"</div>";
518
+
519
+					     // Store the display names for the current number, to be able to see them later
520
+					     let ctPhNumber = phNumberFrom;
521
+					     msgsNamesPerNmbr[ctPhNumber] = displayNames;
522
+
523
+					     // Store the messages sent by each user, to be able to see them later when clicking on the user's name
524
+					     for (let h = 0; h < selectedNames.length; h++) {
525
+
526
+					          let rowMessageArrpn = [];
527
+
528
+					          for (let b = 0; b < convData.length; b++) {
529
+
530
+					               if (selectedNames[h] == convData[b]['author_displayname']) {
531
+
532
+							   if (convData[b]['direction'] == 'sent_from') {
533
+                                                               if (convData[b]['status']) {
534
+							           if (convData[b]['status'].indexOf("delivered") > -1 || convData[b]['status'].indexOf("delivery success") > -1 || convData[b]['status'].indexOf("Retrieved") > -1) {
535
+							               var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
536
+							           } else {
537
+							               var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
538
+							           }
539
+							       } else {
540
+							           var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
541
+                                                               }
542
+							       rowMessageArrpn.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[b]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[b]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[b]['message'] +"</div><div style='display:inline-block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[b]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
543
+							   } else if (convData[b]['direction'] == 'sent_to') {
544
+                                                               if (convData[b]['status']) {
545
+							           if (convData[b]['status'].indexOf("delivered") > -1 || convData[b]['status'].indexOf("delivery success") > -1 || convData[b]['status'].indexOf("Retrieved") > -1) {
546
+							               var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
547
+							           } else {
548
+							               var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
549
+							           }
550
+                                                               } else {
551
+                                                                   var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
552
+                                                               }
553
+							       rowMessageArrpn.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent to current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[b]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[b]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[b]['message'] +"</div><div style='display:inline-block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[b]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
554
+							   } else if (convData[b]['direction'] == 'received_from') {
555
+							       rowMessageArrpn.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[b]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[b]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[b]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[b]['date'] +"</div></div>");
556
+							   } else if (convData[b]['direction'] == 'received_on') {
557
+							       rowMessageArrpn.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received on current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[b]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[b]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[b]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[b]['date'] +"</div></div>");
558
+					                   }
559
+					               }
560
+					          }
561
+					          let crtNmber = phNumberFrom;
562
+					          let crtName = selectedNames[h];
563
+					          msgsNmbrsNames[crtNmber] = msgsNmbrsNames[crtNmber] || {};
564
+		                                  msgsNmbrsNames[crtNmber][crtName] = rowMessageArrpn;
565
+					     }
566
+
567
+		                             // The number of messages to be loaded by default
568
+		                             let nmbTblDefault = 50;
569
+
570
+		                             // If the total number of messages is greater than the default number of messages to display, show the 'Load more messages' button
571
+		                             if (convData.length > nmbTblDefault) {
572
+		                                 $("#loadMoreMsgs").css("display", "block");
573
+		                                 var nmbToBeLoaded = nmbTblDefault;
574
+		                             } else { var nmbToBeLoaded = convData.length; }
575
+
576
+					     let rowMessageArr = [];
577
+
578
+					     for (var m = nmbToBeLoaded - 1; m >= 0; m--) {
579
+
580
+					          if (convData[m]['direction'] == 'sent_from') {
581
+					              if (convData[m]['status']) {
582
+					                  if (convData[m]['status'].indexOf("delivered") > -1 || convData[m]['status'].indexOf("delivery success") > -1 || convData[m]['status'].indexOf("Retrieved") > -1) {
583
+					                      let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
584
+					                  } else {
585
+					                      let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
586
+					                  }
587
+					              } else {
588
+					                  let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
589
+					              }
590
+					              rowMessageArr.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:inline-block;margin:6px 6px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
591
+
592
+					          } else if (convData[m]['direction'] == 'sent_to') {
593
+                                                      if (convData[m]['status']) {
594
+					                  if (convData[m]['status'].indexOf("delivered") > -1 || convData[m]['status'].indexOf("delivery success") > -1 || convData[m]['status'].indexOf("Retrieved") > -1) {
595
+					                      let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
596
+					                  } else {
597
+					                      let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
598
+					                  }
599
+					              } else {
600
+					                  let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
601
+					              }
602
+					              rowMessageArr.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent to current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:inline-block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
603
+
604
+					          } else if (convData[m]['direction'] == 'received_from') {
605
+
606
+						      rowMessageArr.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div></div>");
607
+
608
+					          } else if (convData[m]['direction'] == 'received_on') {
609
+
610
+						      rowMessageArr.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received on current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div></div>");
611
+					          }
612
+					     }
613
+
614
+					     let convDataPerNmbr = rowMessageArr.join("");
615
+		                             $("#grpdbynamelst").empty();
616
+		                             $("#grpdbynamelst").append(displayNames);
617
+		                             $("#msgListRowCell").empty();
618
+		                             $("#msgListRowCell").append(convDataPerNmbr);
619
+
620
+					     // Store the messages for the current number, to be able to see them later, when clicking on the number
621
+					     let rowMessageArrcpt = [];
622
+					     for (let m = 0; m < convData.length; m++) {
623
+
624
+					          if (convData[m]['direction'] == 'sent_from') {
625
+					              if (convData[m]['status']) {
626
+					                  if (convData[m]['status'].indexOf("delivered") > -1 || convData[m]['status'].indexOf("delivery success") > -1 || convData[m]['status'].indexOf("Retrieved") > -1) {
627
+					                      let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
628
+					                  } else {
629
+					                      let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
630
+					                  }
631
+					              } else {
632
+					                  let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
633
+					              }
634
+					              rowMessageArrcpt.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:inline-block;margin:6px 6px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
635
+
636
+					          } else if (convData[m]['direction'] == 'sent_to') {
637
+					              if (convData[m]['status']) {
638
+					                  if (convData[m]['status'].indexOf("delivered") > -1 || convData[m]['status'].indexOf("delivery success") > -1 || convData[m]['status'].indexOf("Retrieved") > -1) {
639
+					                      let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
640
+					                  } else {
641
+					                      let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
642
+					                  }
643
+					              } else {
644
+					                  let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
645
+					              }
646
+					              rowMessageArrcpt.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent to current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:inline-block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
647
+
648
+					          } else if (convData[m]['direction'] == 'received_from') {
649
+
650
+						      rowMessageArrcpt.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div></div>");
651
+
652
+					          } else if (convData[m]['direction'] == 'received_on') {
653
+
654
+						      rowMessageArrcpt.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received on current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div></div>");
655
+					          }
656
+					     }
657
+
658
+					     messagesPerNmbr[phNumberFrom] = rowMessageArrcpt;
659
+
660
+		                             // Scroll down to the bottom of the window
661
+	                                     $("#frmMsgLstWrap").animate({scrollTop:$("#frmMsgLstTbl").prop("scrollHeight")},200);
662
+
663
+		                             // Load more messages
664
+		                             let clickNmb = 0;
665
+		                             $("#loadMoreMsgs").click(function() {
666
+
667
+		                                 clickNmb++;
668
+
669
+		                                 var crefnb = (clickNmb + 1) * nmbToBeLoaded;
670
+
671
+		                                 if (crefnb > convData.length) {
672
+		                                     var nmbmsg = convData.length - 1;
673
+		                                     $("#loadMoreMsgs").css("display", "none");
674
+		                                 } else { 
675
+		                                     var nmbmsg = crefnb - 1;
676
+		                                 }
677
+
678
+		                                 let rowMessageArrAdd = [];
679
+
680
+		                                 for (let m = nmbmsg; m >= clickNmb * nmbToBeLoaded; m--) {
681
+
682
+					              if (convData[m]['direction'] == 'sent_from') {
683
+					                  if (convData[m]['status']) {
684
+					                      if (convData[m]['status'].indexOf("delivered") > -1 || convData[m]['status'].indexOf("delivery success") > -1 || convData[m]['status'].indexOf("Retrieved") > -1) {
685
+					                          let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
686
+					                      } else {
687
+					                          let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
688
+					                      }
689
+					                  } else {
690
+					                      let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
691
+					                  }    
692
+					                  rowMessageArrAdd.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:inline-block;margin:6px 6px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
693
+
694
+					              } else if (convData[m]['direction'] == 'sent_to') {
695
+					                  if (convData[m]['status']) {
696
+					                      if (convData[m]['status'].indexOf("delivered") > -1 || convData[m]['status'].indexOf("delivery success") > -1 || convData[m]['status'].indexOf("Retrieved") > -1) {
697
+					                          let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
698
+					                      } else {
699
+					                          let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
700
+					                      }
701
+					                  } else {
702
+					                      let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
703
+					                  }
704
+					                  rowMessageArrAdd.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent to current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:inline-block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
705
+
706
+					              } else if (convData[m]['direction'] == 'received_from') {
707
+
708
+							  rowMessageArrAdd.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div></div>");
709
+
710
+					              } else if (convData[m]['direction'] == 'received_on') {
711
+
712
+							  rowMessageArrAdd.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received on current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div></div>");
713
+					              }
714
+		                                 }
715
+
716
+					         let convDataPerNmbrad = rowMessageArrAdd.join("");
717
+
718
+		                                 let scrlheight = $("#msgListRowCell").height();
719
+		                                 $("#msgListRowCell").prepend(convDataPerNmbrad);
720
+
721
+		                                 $("#frmMsgLstWrap").scrollTop($("#msgListRowCell").height() - scrlheight);
722
+		                             });
723
+
724
+
725
+					     // Show the messages sent by each user whose name is clicked
726
+					     $('[id*="diplNm_"]').click(function() {
727
+
728
+					         let crntNmbr = $(this).attr("id").split("_")[1];
729
+					         let crntDisName = $(this).attr("name");                               
730
+		                                 $("#loadMoreMsgs").css("display", "none");
731
+
732
+		                                 let convDataprn = [];
733
+		                                 $.each(msgsNmbrsNames[crntNmbr][crntDisName], function(index, item) {
734
+		                                        convDataprn.push(item);
735
+		                                 });
736
+
737
+		                                 // If the total number of messages is greater than the default number of messages to display, show the 'Load more messages' button
738
+		                                 if (convDataprn.length > nmbTblDefault) {
739
+		                                     $("#loadMoreMsgsusr").css("display", "block");
740
+		                                     let nmbToBeLoaded = nmbTblDefault;
741
+		                                 } else {
742
+		                                     $("#loadMoreMsgsusr").css("display", "none");
743
+		                                     let nmbToBeLoaded = convDataprn.length;
744
+		                                 }
745
+
746
+					         let rowMessageArrprnst = [];
747
+
748
+					         for (let n = nmbToBeLoaded - 1; n >= 0; n--) {
749
+		                                      rowMessageArrprnst.push(convDataprn[n]);
750
+					         }
751
+
752
+					         let convDataPerNmbrprnst = rowMessageArrprnst.join("");
753
+
754
+		                                 $("#msgListRowCell").empty();
755
+		                                 $("#msgListRowCell").append(convDataPerNmbrprnst);
756
+
757
+		                                 // Scroll down to the bottom of the window
758
+		                                 $("#frmMsgLstWrap").animate({scrollTop:$("#frmMsgLstTbl").prop("scrollHeight")},200);
759
+
760
+		                                 // Load more messages
761
+		                                 let clckNb = 0;
762
+		                                 $("#loadMoreMsgsusr").unbind("click");
763
+		                                 $("#loadMoreMsgsusr").click(function() {
764
+
765
+		                                     clckNb++;
766
+		                                     var crefnb = (clckNb + 1) * nmbToBeLoaded;
767
+
768
+		                                     $("#loadMoreMsgs").css("display", "none");
769
+
770
+		                                     if (crefnb > convDataprn.length) {
771
+		                                         var nmbmsg = convDataprn.length - 1;
772
+		                                         $("#loadMoreMsgsusr").css("display", "none");
773
+		                                     } else { 
774
+		                                         var nmbmsg = crefnb - 1;
775
+		                                         $("#loadMoreMsgsusr").css("display", "block");
776
+		                                     }
777
+
778
+		                                     var rowMessageArrAddst = [];
779
+
780
+		                                     for (var q = nmbmsg; q >= clckNb * nmbToBeLoaded; q--) {
781
+
782
+		                                          rowMessageArrAddst.push(convDataprn[q]);
783
+		                                     }
784
+
785
+					             var convDataPerNmbradst = rowMessageArrAddst.join("");
786
+
787
+		                                     var scrlheight = $("#msgListRowCell").height();
788
+		                                     $("#msgListRowCell").prepend(convDataPerNmbradst);
789
+
790
+		                                     $("#frmMsgLstWrap").scrollTop($("#msgListRowCell").height() - scrlheight);
791
+		                                 });
792
+
793
+
794
+					         $(".dispNameList").each(function() { $(this).css("color", "#0a559e"); });
795
+					         $("#diplNmAllMsg").css("color", "#04957b");
796
+					         $(this).css("color", "#1b8efe");
797
+					     });
798
+
799
+
800
+					     // Show again all the messages sent/received to/from the clicked number
801
+					     $("#diplNmAllMsg").click(function() {
802
+
803
+		                                 $("#loadMoreMsgsusr").css("display", "none");
804
+
805
+		                                 let convDataprn = [];
806
+		                                 $.each(messagesPerNmbr[phNumberFrom], function(index, item) {
807
+		                                        convDataprn.push(item);
808
+		                                 });
809
+
810
+		                                 // If the total number of messages is greater than the default number of messages to display, show the 'Load more messages' button
811
+		                                 if (convDataprn.length > nmbTblDefault) {
812
+		                                     $("#loadMoreMsgs").css("display", "block");
813
+		                                     let nmbToBeLoaded = nmbTblDefault;
814
+		                                 } else {
815
+		                                     $("#loadMoreMsgs").css("display", "none");
816
+		                                     let nmbToBeLoaded = convDataprn.length;
817
+		                                 }
818
+
819
+					         let rowMessageArrprnst = [];
820
+
821
+					         for (let n = nmbToBeLoaded - 1; n >= 0; n--) {
822
+		                                      rowMessageArrprnst.push(convDataprn[n]);
823
+					         }
824
+
825
+					         let convDataPerNmbrprnst = rowMessageArrprnst.join("");
826
+
827
+		                                 $("#msgListRowCell").empty();
828
+		                                 $("#msgListRowCell").append(convDataPerNmbrprnst);
829
+
830
+		                                 // Scroll down to the bottom of the window
831
+		                                 $("#frmMsgLstWrap").animate({scrollTop:$("#frmMsgLstTbl").prop("scrollHeight")},200);
832
+
833
+
834
+		                                 // Load more messages
835
+		                                 let clckNb = 0;
836
+		                                 $("#loadMoreMsgs").unbind("click");
837
+		                                 $("#loadMoreMsgs").click(function() {
838
+
839
+		                                     clckNb++;
840
+		                                     var crefnb = (clckNb + 1) * nmbToBeLoaded;
841
+
842
+		                                     $("#loadMoreMsgsusr").css("display", "none");
843
+
844
+		                                     if (crefnb > convDataprn.length) {
845
+		                                         var nmbmsg = convDataprn.length - 1;
846
+		                                         $("#loadMoreMsgs").css("display", "none");
847
+		                                     } else {
848
+		                                         var nmbmsg = crefnb - 1;
849
+		                                         $("#loadMoreMsgs").css("display", "block");
850
+		                                     }
851
+
852
+		                                     let rowMessageArrAddst = [];
853
+
854
+		                                     for (var q = nmbmsg; q >= clckNb * nmbToBeLoaded; q--) {
855
+
856
+		                                          rowMessageArrAddst.push(convDataprn[q]);
857
+		                                     }
858
+
859
+					             let convDataPerNmbradst = rowMessageArrAddst.join("");
860
+
861
+		                                     let scrlheight = $("#msgListRowCell").height();
862
+		                                     $("#msgListRowCell").prepend(convDataPerNmbradst);
863
+
864
+		                                     $("#frmMsgLstWrap").scrollTop($("#msgListRowCell").height() - scrlheight);
865
+
866
+		                                 });
867
+
868
+					         $(".dispNameList").each(function() { $(this).css("color", "#0a559e"); });
869
+					         $("#diplNmAllMsg").css("color", "#04957b");
870
+					         $(this).css("color", "#04c6a4");
871
+
872
+					     });
873
+
874
+
875
+					     // Show the scroll-up arrow
876
+					     $("#frmMsgLstWrap").scroll(function() {
877
+						if ($(this).scrollTop() > 900) {
878
+						      $('#upArrowSmall').fadeIn();
879
+						} else {
880
+						      $('#upArrowSmall').fadeOut();
881
+						}
882
+					     });
883
+
884
+					     $("#upArrowSmall").click(function() {
885
+						$("#frmMsgLstWrap").animate({scrollTop : 0},400);
886
+					     });
887
+
888
+
889
+					     // Download MMS files when clicking on their URLs
890
+					     $('[id^="mmsTblUrl-"]').on('click', function(evt) {
891
+
892
+					        var clckedUrl = $(this).text();
893
+					        var flNamearr = clckedUrl.split("/");
894
+					        var flName = flNamearr.reverse()[0];
895
+
896
+					        confirmAlert("Download this file only if you trust the sender and the domain of the URL.");
897
+
898
+					        $("#confirmOk").click(function() {
899
+
900
+					           $("#alertMsgOverlay").remove();
901
+					           $("#alertConfMessage").remove();
902
+
903
+					           var mmsLink = document.createElement("a");
904
+					           mmsLink.setAttribute('href', clckedUrl);
905
+					           mmsLink.setAttribute('download', flName);
906
+                                                   mmsLink.setAttribute('target', '_blank');
907
+					           document.body.appendChild(mmsLink);
908
+					           mmsLink.click();
909
+					           mmsLink.remove();
910
+					        });
911
+
912
+					        $("#confirmCancel").click(function() { $("#alertMsgOverlay").remove(); $("#alertConfMessage").remove(); });
913
+					     });
914
+
915
+				  },
916
+				  error: function() {
917
+		                             showAlert("Error while attempting to get message data from the database!");
918
+					     $('#listAllMsgsConv').removeClass('icon-loading');
919
+				  }
920
+			   });
921
+
922
+                           // Scroll down to the bottom of the window
923
+                           $("#frmMsgLstWrap").animate({scrollTop:$("#frmMsgLstTbl").prop("scrollHeight")},200);
924
+                   }
925
+
926
+                   getMsgsForNumbers(phNumberFrom, phNumberTo);
927
+
928
+                   $("#refreshMsgsConv").click(function() { getMsgsForNumbers(phNumberFrom, phNumberTo); setTimeout(function() { $("#diplNmAllMsg").click(); }, 1000); });
929
+                }
930
+
931
+                $('[id^="showMsgConv-"]').click(function() {
932
+
933
+                   let ctrwnmbr = $(this).attr("id").replace("showMsgConv-", "");
934
+                   let phNumberFrom = $("#frmNmbr-"+ ctrwnmbr).text();
935
+                   let phNumberTo = $("#toNmbr-"+ ctrwnmbr).text().split(": ")[1];
936
+
937
+                   showRecMsgPerConv(phNumberFrom, phNumberTo);
938
+                });
939
+
940
+
941
+                // Show the pop-up window that lists all the messages sent/received to/from a phone number
942
+                function showMsgPerNmbr(clckPhNumber) {
943
+
944
+                   var allfrmtomsg = "<div id='listAllMsgsFromTo'>";
945
+                   allfrmtomsg += "<div id='draglstMsgmWindow'><img src='/" + ctappdir + "/sms_relentless/img/dots.svg'></div>";
946
+                   allfrmtomsg += "<a id='closeFrmMsgWindow' title='Close this window'></a>";
947
+                   allfrmtomsg += "<div class='showByNmbrTitle'>Messages sent/received to/from  <span style='color:#04957b'>"+ clckPhNumber +"</span></div>";
948
+                   allfrmtomsg += "<div id='frmMsgLstWrap'>";
949
+                   allfrmtomsg += "<table id='frmMsgLstTbl'>";
950
+                   allfrmtomsg += "<tr class='groupedrowsbody'><td><div id='grpdbynamelst' class='groupedLstNamespn'></div></td><td><div id='loadMoreMsgs' title='Click to load older messages.'>Load more messages</div><div id='loadMoreMsgsusr' title='Click to load older messages.'>Load more messages</div><div id='msgListRowCell' class='groupedLstMsgspn'></div><div id='refreshMsgsWraptf'><div id='refreshMsgsConvtf' title='Refresh list of messages'></div></div><div id='arrowupWrap'><div id='upArrowSmall' title='Scroll to the top'></div></div></td></tr>";
951
+                   allfrmtomsg += "</table></div>";
952
+                   allfrmtomsg += "<div id='sendMsgReply'><table id='sendMsgConv'><tr><td><div id='fromPhoneNmbrConv'>From: <select id='selectFromNbConv'></select></div><div id='toPhoneNmbrConv'>To: <span id='toNmbrConv' style='color:#04957b'>"+ clckPhNumber +"</span></div></td></tr>";
953
+                   allfrmtomsg += "<tr><td><textarea id='sendMsgConvText' placeholder='Enter a message here, then press Send SMS'></textarea></td></tr></table>";
954
+                   allfrmtomsg += "<div id='sendMsgConvBtn'>Send SMS</div></div>";
955
+                   allfrmtomsg += "<div style='display:block;width:100%;height:14px;'><img id='expandWindowRpl' src='/" + ctappdir + "/sms_relentless/img/arrowDown.svg' title='Expand to send a message'></div>";
956
+                   allfrmtomsg += "<div id='draglstMsgmWindowsc'><img src='/" + ctappdir + "/sms_relentless/img/dots.svg' style='padding:4px;vertical-align:top;'></div>";
957
+                   allfrmtomsg += "</div>";
958
+
959
+                   $("#content").append("<div id='recTblOverlay'></div>");
960
+                   $("#content").append(allfrmtomsg);
961
+
962
+                   var topDist = parseInt((window.innerHeight / 2).toFixed(2) - 340) +"px";
963
+                   var leftDist = parseInt((window.innerWidth / 2).toFixed(2) - 300) +"px";
964
+                   $("#listAllMsgsFromTo").css({ "top" : topDist, "left" : leftDist });
965
+
966
+                   $("#closeFrmMsgWindow").click(function() { $("#listAllMsgsFromTo").remove(); $("#recTblOverlay").remove(); });
967
+                   $("#recTblOverlay").click(function() { $("#listAllMsgsFromTo").remove(); $("#recTblOverlay").remove(); });
968
+
969
+	           // Expand the window when clicking on the arrow, to be able to send a reply message
970
+                   $("#expandWindowRpl").unbind("click");
971
+	           $("#expandWindowRpl").click(function() {
972
+
973
+	              if ($(this).attr('src') == '/' + ctappdir + '/sms_relentless/img/arrowDown.svg') {
974
+                          $("#sendMsgReply").css("display", "block");
975
+                          $("#listAllMsgsFromTo").css("height", "618px");
976
+	                  $(this).attr('src', '/' + ctappdir + '/sms_relentless/img/arrowUp.svg');
977
+                          $(this).attr('title', 'Collapse');
978
+
979
+	              } else {
980
+
981
+                          $("#sendMsgReply").css("display", "none");
982
+                          $("#listAllMsgsFromTo").css("height", "490px");
983
+                          $(this).attr('src', '/' + ctappdir + '/sms_relentless/img/arrowDown.svg');
984
+                          $(this).attr('title', 'Expand to send a reply');
985
+	              }
986
+	           });
987
+
988
+
989
+                   // Send a message from the 'conversation' window
990
+                   $("#sendMsgConvBtn").click(function() {
991
+
992
+                      $("#sendMsgConv,#sendMsgConvBtn").addClass('icon-loading');
993
+                      var msgToSend = $("#sendMsgConvText").val();
994
+                      var selectedid = $("#selectFromNbConv").val();
995
+                      var toNumber = $("#toNmbrConv").text();
996
+                      var receiversNumbers = [toNumber];
997
+
998
+		      if (selectedid != '') { 
999
+
1000
+			  var sendersplit = selectedid.split(":");
1001
+			  var providercap = sendersplit[0];
1002
+			  var provsec = sendersplit[1];
1003
+
1004
+			  if (/[a-zA-Z]/.test(provsec)) {
1005
+			      var alphanumcheck = true;
1006
+			  } else { var alphanumcheck = false; }
1007
+
1008
+			  if (providercap == 'Tx' && alphanumcheck == false) {  
1009
+			      var senderproc = selectedid.replace(/[^0-9]/g, "");
1010
+			      var selectedsender = "+" + senderproc;
1011
+			      var providerUsed = "telnyx";
1012
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmstel");
1013
+			  } else if (providercap == 'Pl' && alphanumcheck == false) {
1014
+			      var selectedsender = selectedid.replace(/[^0-9]/g, "");
1015
+			      var providerUsed = "plivo";
1016
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmsnex");
1017
+			  } else if (providercap == 'Tw' && alphanumcheck == false) {  
1018
+			      var senderproc = selectedid.replace(/[^0-9]/g, "");
1019
+			      var selectedsender = "+" + senderproc;
1020
+			      var providerUsed = "twilio";
1021
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmstwil");
1022
+			  } else if (providercap == 'Fl' && alphanumcheck == false) {  
1023
+			      var senderproc = selectedid.replace(/[^0-9]/g, "");
1024
+			      var selectedsender = "+" + senderproc;
1025
+			      var providerUsed = "flowroute";
1026
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmsflow");
1027
+			  } else if (providercap == 'Tx' && alphanumcheck == true) {
1028
+			      var selectedsender = provsec;
1029
+			      var providerUsed = "telnyx";
1030
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmstel");
1031
+			  } else if (providercap == 'Pl' && alphanumcheck == true) {
1032
+			      var selectedsender = provsec;
1033
+			      var providerUsed = "plivo";
1034
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmsnex");
1035
+			  } else if (providercap == 'Tw' && alphanumcheck == true) {
1036
+			      var selectedsender = provsec;
1037
+			      var providerUsed = "twilio";
1038
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmstwil");
1039
+			  } else if (providercap == 'Fl' && alphanumcheck == true) {
1040
+			      var selectedsender = provsec;
1041
+			      var providerUsed = "flowroute";
1042
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmsflow");
1043
+			  }
1044
+
1045
+                          var uploadedtomms = [];
1046
+
1047
+	                  if (msgToSend != '') {
1048
+
1049
+				  $.ajax({
1050
+				     url: relbaseUrl + '/' + userid,
1051
+				     type: "POST",
1052
+				     data: {
1053
+				           receiversPhoneNbs: receiversNumbers,
1054
+				           fromsender: selectedsender,
1055
+				           waitinterval: 1000,
1056
+				           sentsmstext: msgToSend,
1057
+				           ismms: 0,
1058
+				           mmsfiles: uploadedtomms
1059
+				         },
1060
+				     success: function(displayname) {
1061
+
1062
+                                           var tzdate = new Date();
1063
+                                           var presDatest = new Date(tzdate.getTime() - (tzdate.getTimezoneOffset() * 60000)).toJSON();
1064
+                                           var presDatedb = presDatest.split(".")[0];
1065
+                                           var presDatesc = presDatedb.split("T");
1066
+                                           var presDate = presDatesc[0] +" "+ presDatesc[1];
1067
+                                           var sentMessageStatus = '';
1068
+
1069
+                                           if (displayname) {
1070
+                                               var msgToSendproc = "<span class='msgAuthorNameGrp'>"+ displayname + ":</span>" + msgToSend; 
1071
+                                           } else { var msgToSendproc = msgToSend; }
1072
+
1073
+                                           $("#msgListRowCell").append("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent to current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ selectedsender +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ receiversNumbers[0] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ msgToSendproc +"</div><div style='display:inline-block;margin:6px 6px 0px 4px;font-size:12.5px;color:#353535;'>"+ presDate +"</div><div class='sentMssgStatus'>"+ sentMessageStatus +"</div></div>");
1074
+
1075
+                                           // Scroll down to the bottom of the window
1076
+                                           $("#frmMsgLstWrap").animate({scrollTop:$("#frmMsgLstTbl").prop("scrollHeight")},200);
1077
+
1078
+                                           $("#sendMsgConv,#sendMsgConvBtn").removeClass('icon-loading');
1079
+				     },
1080
+				     error: function() {
1081
+                                           showAlert("Error while sending the message. You can check your Nextcloud log to find out more about this issue.");
1082
+				           $("#sendMsgConv,#sendMsgConvBtn").removeClass('icon-loading');
1083
+				     }
1084
+				  });
1085
+			  } else {
1086
+                                  showAlert("Please enter a message in the text box!");
1087
+				  $("#sendMsgConv,#sendMsgConvBtn").removeClass('icon-loading');
1088
+			  }
1089
+		      } else {
1090
+                              showAlert("Please choose a Sender ID from the 'From' drop-down list!");
1091
+			      $("#sendMsgConv,#sendMsgConvBtn").removeClass('icon-loading');
1092
+		      }
1093
+
1094
+                   });
1095
+
1096
+
1097
+	           // Make the window draggable
1098
+	           function makeMgrWndDraggable(e) {
1099
+
1100
+			   window.pmdragging = {};
1101
+			   pmdragging.pageX0 = e.pageX;
1102
+			   pmdragging.pageY0 = e.pageY;
1103
+			   pmdragging.elem = $("#listAllMsgsFromTo");
1104
+			   pmdragging.offset0 = $("#listAllMsgsFromTo").offset();
1105
+
1106
+			   function handle_dragging(e) {
1107
+			       var left = pmdragging.offset0.left + (e.pageX - pmdragging.pageX0);
1108
+			       var top = pmdragging.offset0.top + (e.pageY - pmdragging.pageY0);
1109
+			       $(pmdragging.elem).offset({top: top, left: left});
1110
+			   }
1111
+
1112
+			   function handle_mouseup(e) {
1113
+			       $('body').off('mousemove', handle_dragging).off('mouseup', handle_mouseup);
1114
+			   }
1115
+
1116
+			   $('body').on('mouseup', handle_mouseup).on('mousemove', handle_dragging);
1117
+	           }
1118
+	           $("#draglstMsgmWindow").mousedown(makeMgrWndDraggable);
1119
+	           $("#draglstMsgmWindowsc").mousedown(makeMgrWndDraggable);
1120
+
1121
+
1122
+                   // Append the available phone numbers to the From drop-down list
1123
+                   var availPhoneNmbrs = [];
1124
+                   $("#currentsmsnmbrs .optselectsmsnb").each(function() {
1125
+                      var crtphnmbr = $(this).attr("value");
1126
+                      if (crtphnmbr != "") { availPhoneNmbrs.push(crtphnmbr); }
1127
+                   });
1128
+
1129
+                   if (availPhoneNmbrs.length > 0) {
1130
+                       var avphopt = "";
1131
+                       for (let d = 0; d < availPhoneNmbrs.length; d++) {
1132
+                            avphopt += "<option value='"+ availPhoneNmbrs[d] +"'>"+ availPhoneNmbrs[d] +"</option>";
1133
+                       }
1134
+                       $("#selectFromNbConv").append(avphopt);
1135
+
1136
+                   } else { $("#selectFromNbConv").append("<option value='' selected>No IDs</option>"); }
1137
+
1138
+
1139
+                   // Get the sent/received messages for the current phone number, from the database
1140
+                   function getMsgsPerNmbr(clckPhNumber) {
1141
+
1142
+			   var getGroupedPnUrl = OC.generateUrl("/apps/sms_relentless/user/getgroupedpernumber");
1143
+
1144
+			   $('#listAllMsgsFromTo').addClass('icon-loading');
1145
+			   var totalPhNmbrs = 0;
1146
+
1147
+			   $.ajax({
1148
+				  method: 'POST',
1149
+				  url: getGroupedPnUrl + '/' + userid,
1150
+				  contentType: 'application/json',
1151
+		                  data: JSON.stringify({ phoneNumber: clckPhNumber }),
1152
+				  success: function(groupedpernb) {
1153
+
1154
+					     $('#listAllMsgsFromTo').removeClass('icon-loading');
1155
+
1156
+					     var fromtoNmbrsData = [];
1157
+
1158
+					     for (var i = 0; i < groupedpernb.length; i++) {
1159
+
1160
+						     if (groupedpernb[i].author_displayname) {
1161
+							 var authordnm = groupedpernb[i].author_displayname;
1162
+						     } else { 
1163
+							 var authordnm = '';
1164
+						     }
1165
+
1166
+						     var sentfromnmbrarr = groupedpernb[i].from.split(": ");
1167
+						     if (sentfromnmbrarr[1]) {
1168
+							 var groupednbfrom = sentfromnmbrarr[1];
1169
+						     } else {
1170
+							 var groupednbfrom = sentfromnmbrarr[0];
1171
+						     }
1172
+
1173
+						     var modmessagerec = '';
1174
+						     if (groupedpernb[i].author_displayname) {
1175
+							 modmessagerec = "<span class='msgAuthorNameGrp'>"+ groupedpernb[i].author_displayname + ":</span>" + groupedpernb[i].message;
1176
+						     } else {
1177
+					                 modmessagerec = groupedpernb[i].message;
1178
+		                                     }
1179
+
1180
+						     if (groupedpernb[i].to.indexOf(": ") > -1) {
1181
+						         var groupednmbrtopre = groupedpernb[i].to.split(": ");
1182
+						         var groupednmbrto = groupednmbrtopre[1];
1183
+						     } else { 
1184
+						         var groupednmbrto = groupedpernb[i].to;
1185
+						     }
1186
+
1187
+						     fromtoNmbrsData.push({
1188
+						               'author_displayname': authordnm,
1189
+						               'from': groupednbfrom,
1190
+						               'to': groupednmbrto,
1191
+						               'message': modmessagerec,
1192
+						               'date': groupedpernb[i].date,
1193
+						               'status': groupedpernb[i].deliveryreceipt,
1194
+						               'table': groupedpernb[i].table
1195
+						     });
1196
+					     }
1197
+
1198
+
1199
+					     // Remove the duplicates
1200
+					     var noDupMsgData = [];
1201
+					     $.each(fromtoNmbrsData, function(i, e) {
1202
+						    var matchingData = $.grep(noDupMsgData, function(item) {
1203
+						            return item.from == e.from && item.to == e.to && item.message == e.message && item.table == 'received' && e.table == 'sent';
1204
+						    });
1205
+						    if (matchingData.length === 0) {
1206
+							noDupMsgData.push(e);
1207
+						    }
1208
+					     });
1209
+
1210
+					     var messagesPerNmbr = {};
1211
+					     var msgsNamesPerNmbr = {};
1212
+					     var msgsNmbrsNames = {};
1213
+
1214
+					     var displayNamesarr = [];
1215
+					     var convData = [];
1216
+
1217
+					     for (var n = 0; n < noDupMsgData.length; n++) {
1218
+
1219
+					          if (noDupMsgData[n]['from'] == clckPhNumber && noDupMsgData[n]['table'] == 'sent') {
1220
+
1221
+					              convData.push({
1222
+					                             'author_displayname': noDupMsgData[n]['author_displayname'],
1223
+					                             'message': noDupMsgData[n]['message'],
1224
+					                             'from': noDupMsgData[n]['from'],
1225
+					                             'to': noDupMsgData[n]['to'],
1226
+					                             'date': noDupMsgData[n]['date'],
1227
+					                             'direction': 'sent_from',
1228
+					                             'status': (noDupMsgData[n]['status'] == null)? "" : noDupMsgData[n]['status'],
1229
+					                             'table': noDupMsgData[n]['table']
1230
+					              });
1231
+
1232
+					          } else if (noDupMsgData[n]['to'] == clckPhNumber && noDupMsgData[n]['table'] == 'sent') {
1233
+
1234
+					              convData.push({
1235
+					                             'author_displayname': noDupMsgData[n]['author_displayname'],
1236
+					                             'message': noDupMsgData[n]['message'],
1237
+					                             'from': noDupMsgData[n]['from'],
1238
+					                             'to': noDupMsgData[n]['to'],
1239
+					                             'date': noDupMsgData[n]['date'],
1240
+					                             'direction': 'sent_to',
1241
+					                             'status': (noDupMsgData[n]['status'] == null)? "" : noDupMsgData[n]['status'],
1242
+					                             'table': noDupMsgData[n]['table']
1243
+					              });
1244
+
1245
+
1246
+					          } else if (noDupMsgData[n]['from'] == clckPhNumber && noDupMsgData[n]['table'] == 'received') {
1247
+
1248
+					              convData.push({
1249
+					                             'author_displayname': noDupMsgData[n]['author_displayname'],
1250
+					                             'message': noDupMsgData[n]['message'],
1251
+					                             'from': noDupMsgData[n]['from'],
1252
+					                             'to': noDupMsgData[n]['to'],
1253
+					                             'date': noDupMsgData[n]['date'],
1254
+					                             'direction': 'received_from',
1255
+					                             'status': (noDupMsgData[n]['status'] == null)? "" : noDupMsgData[n]['status'],
1256
+					                             'table': noDupMsgData[n]['table']
1257
+					              });
1258
+
1259
+					          } else if (noDupMsgData[n]['to'] == clckPhNumber && noDupMsgData[n]['table'] == 'received') {
1260
+
1261
+					              convData.push({
1262
+					                             'author_displayname': noDupMsgData[n]['author_displayname'],
1263
+					                             'message': noDupMsgData[n]['message'],
1264
+					                             'from': noDupMsgData[n]['from'],
1265
+					                             'to': noDupMsgData[n]['to'],
1266
+					                             'date': noDupMsgData[n]['date'],
1267
+					                             'direction': 'received_on',
1268
+					                             'status': (noDupMsgData[n]['status'] == null)? "" : noDupMsgData[n]['status'],
1269
+					                             'table': noDupMsgData[n]['table']
1270
+					              });
1271
+					          }
1272
+					     }
1273
+
1274
+					     // Sort messages by date
1275
+					     convData.sort(function(a, b) {
1276
+						var c = new Date(a.date);
1277
+						var d = new Date(b.date);
1278
+						return c-d;
1279
+					     });
1280
+		                             convData.reverse();
1281
+
1282
+					     // Collect the display names of the users that sent messages from the current number
1283
+					     var selectedNames = [];
1284
+					     var displayNames = '';
1285
+					     for (var v = 0; v < convData.length; v++) {
1286
+					          if (selectedNames.indexOf(convData[v]['author_displayname']) == -1) { 
1287
+					              selectedNames.push(convData[v]['author_displayname']);
1288
+					              displayNames += "<div id='diplNm_"+ clckPhNumber +"_"+ v +"' class='dispNameList' name='"+ convData[v]['author_displayname'] +"'>"+ convData[v]['author_displayname'] +"</div>";
1289
+					          }
1290
+					     }
1291
+					     displayNames += "<div id='diplNmAllMsg' class='dispNameListAll' title='Show all the messages for this number.'>"+ clckPhNumber +"</div>";
1292
+
1293
+					     // Store the display names for the current number, to be able to see them later
1294
+					     var ctPhNumber = clckPhNumber;
1295
+					     msgsNamesPerNmbr[ctPhNumber] = displayNames;
1296
+
1297
+					     // Store the messages sent by each user, to be able to see them later when clicking on the user's name
1298
+					     for (var h = 0; h < selectedNames.length; h++) {
1299
+
1300
+					          var rowMessageArrpn = [];
1301
+					          for (var b = 0; b < convData.length; b++) {
1302
+
1303
+					               if (selectedNames[h] == convData[b]['author_displayname']) {
1304
+
1305
+							   if (convData[b]['direction'] == 'sent_from') {
1306
+							       if (convData[b]['status']) {
1307
+							           if (convData[b]['status'].indexOf("delivered") > -1 || convData[b]['status'].indexOf("delivery success") > -1 || convData[b]['status'].indexOf("Retrieved") > -1) {
1308
+							               var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
1309
+							           } else {
1310
+							               var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
1311
+							           }
1312
+							       } else {
1313
+							               var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
1314
+							       }
1315
+							       rowMessageArrpn.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[b]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[b]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[b]['message'] +"</div><div style='display:inline-block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[b]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
1316
+							   } else if (convData[b]['direction'] == 'sent_to') {
1317
+							       if (convData[b]['status']) {
1318
+							           if (convData[b]['status'].indexOf("delivered") > -1 || convData[b]['status'].indexOf("delivery success") > -1 || convData[b]['status'].indexOf("Retrieved") > -1) {
1319
+							               var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
1320
+							           } else {
1321
+							               var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
1322
+							           }
1323
+							       } else {
1324
+							           var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
1325
+							       }
1326
+							       rowMessageArrpn.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent to current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[b]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[b]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[b]['message'] +"</div><div style='display:inline-block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[b]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
1327
+							   } else if (convData[b]['direction'] == 'received_from') {
1328
+							       rowMessageArrpn.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[b]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[b]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[b]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[b]['date'] +"</div></div>");
1329
+							   } else if (convData[b]['direction'] == 'received_on') {
1330
+							       rowMessageArrpn.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received on current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[b]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[b]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[b]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[b]['date'] +"</div></div>");
1331
+					                   }
1332
+					               }
1333
+					          }
1334
+					          var crtNmber = clckPhNumber;
1335
+					          var crtName = selectedNames[h];
1336
+					          msgsNmbrsNames[crtNmber] = msgsNmbrsNames[crtNmber] || {};
1337
+		                                  msgsNmbrsNames[crtNmber][crtName] = rowMessageArrpn;
1338
+					     }
1339
+
1340
+		                             // The number of messages to be loaded by default
1341
+		                             var nmbTblDefault = 50;
1342
+
1343
+		                             // If the total number of messages is greater than the default number of messages to display, show the 'Load more messages' button
1344
+		                             if (convData.length > nmbTblDefault) {
1345
+		                                 $("#loadMoreMsgs").css("display", "block");
1346
+		                                 var nmbToBeLoaded = nmbTblDefault;
1347
+		                             } else { var nmbToBeLoaded = convData.length; }
1348
+
1349
+					     var rowMessageArr = [];
1350
+					     for (var m = nmbToBeLoaded - 1; m >= 0; m--) {
1351
+
1352
+					          if (convData[m]['direction'] == 'sent_from') {
1353
+					              if (convData[m]['status']) {
1354
+					                  if (convData[m]['status'].indexOf("delivered") > -1 || convData[m]['status'].indexOf("delivery success") > -1 || convData[m]['status'].indexOf("Retrieved") > -1) {
1355
+					                      var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
1356
+					                  } else {
1357
+					                      var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
1358
+					                  }
1359
+					              } else {
1360
+					                  var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
1361
+					              }
1362
+					              rowMessageArr.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:inline-block;margin:6px 6px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
1363
+
1364
+					          } else if (convData[m]['direction'] == 'sent_to') {
1365
+					              if (convData[m]['status']) {
1366
+					                  if (convData[m]['status'].indexOf("delivered") > -1 || convData[m]['status'].indexOf("delivery success") > -1 || convData[m]['status'].indexOf("Retrieved") > -1) {
1367
+					                      var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
1368
+					                  } else {
1369
+					                      var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
1370
+					                  }
1371
+					              } else {
1372
+					                  var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
1373
+					              }
1374
+					              rowMessageArr.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent to current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:inline-block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
1375
+
1376
+					          } else if (convData[m]['direction'] == 'received_from') {
1377
+
1378
+						      rowMessageArr.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div></div>");
1379
+
1380
+					          } else if (convData[m]['direction'] == 'received_on') {
1381
+
1382
+						      rowMessageArr.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received on current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div></div>");
1383
+					          }
1384
+					     }
1385
+
1386
+					     var convDataPerNmbr = rowMessageArr.join("");
1387
+
1388
+		                             $("#grpdbynamelst").empty();
1389
+		                             $("#grpdbynamelst").append(displayNames);
1390
+		                             $("#msgListRowCell").empty();
1391
+		                             $("#msgListRowCell").append(convDataPerNmbr);
1392
+
1393
+					     // Store the messages for the current number, to be able to see them later, when clicking on the number
1394
+					     var rowMessageArrcpt = [];
1395
+					     for (var m = 0; m < convData.length; m++) {
1396
+
1397
+					          if (convData[m]['direction'] == 'sent_from') {
1398
+					              if (convData[m]['status']) {
1399
+					                  if (convData[m]['status'].indexOf("delivered") > -1 || convData[m]['status'].indexOf("delivery success") > -1 || convData[m]['status'].indexOf("Retrieved") > -1) {
1400
+					                      var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
1401
+					                  } else {
1402
+					                      var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
1403
+					                  }
1404
+					              } else {
1405
+					                  var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
1406
+					              }
1407
+					              rowMessageArrcpt.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:inline-block;margin:6px 6px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
1408
+
1409
+					          } else if (convData[m]['direction'] == 'sent_to') {
1410
+					              if (convData[m]['status']) {
1411
+					                  if (convData[m]['status'].indexOf("delivered") > -1 || convData[m]['status'].indexOf("delivery success") > -1 || convData[m]['status'].indexOf("Retrieved") > -1) {
1412
+					                      var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
1413
+					                  } else {
1414
+					                      var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
1415
+					                  }
1416
+					              } else {
1417
+					                  var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
1418
+					              }
1419
+					              rowMessageArrcpt.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent to current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:inline-block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
1420
+
1421
+					          } else if (convData[m]['direction'] == 'received_from') {
1422
+
1423
+						      rowMessageArrcpt.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div></div>");
1424
+
1425
+					          } else if (convData[m]['direction'] == 'received_on') {
1426
+
1427
+						      rowMessageArrcpt.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received on current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div></div>");
1428
+					          }
1429
+					     }
1430
+
1431
+					     messagesPerNmbr[clckPhNumber] = rowMessageArrcpt;
1432
+
1433
+		                             // Scroll down to the bottom of the window
1434
+	                                     $("#frmMsgLstWrap").animate({scrollTop:$("#frmMsgLstTbl").prop("scrollHeight")},200);
1435
+
1436
+		                             // Load more messages
1437
+		                             var clickNmb = 0;
1438
+		                             $("#loadMoreMsgs").click(function() {
1439
+
1440
+		                                 clickNmb++;
1441
+
1442
+		                                 var crefnb = (clickNmb + 1) * nmbToBeLoaded;
1443
+
1444
+		                                 if (crefnb > convData.length) {
1445
+		                                     var nmbmsg = convData.length - 1;
1446
+		                                     $("#loadMoreMsgs").css("display", "none");
1447
+		                                 } else { 
1448
+		                                     var nmbmsg = crefnb - 1;
1449
+		                                 }
1450
+
1451
+		                                 var rowMessageArrAdd = [];
1452
+
1453
+		                                 for (var m = nmbmsg; m >= clickNmb * nmbToBeLoaded; m--) {
1454
+
1455
+					              if (convData[m]['direction'] == 'sent_from') {
1456
+					                  if (convData[m]['status']) {
1457
+					                      if (convData[m]['status'].indexOf("delivered") > -1 || convData[m]['status'].indexOf("delivery success") > -1 || convData[m]['status'].indexOf("Retrieved") > -1) {
1458
+					                          var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
1459
+					                      } else {
1460
+					                          var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
1461
+					                      }
1462
+					                  } else {
1463
+					                      var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
1464
+					                  }
1465
+					                  rowMessageArrAdd.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:inline-block;margin:6px 6px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
1466
+
1467
+					              } else if (convData[m]['direction'] == 'sent_to') {
1468
+					                  if (convData[m]['status']) {
1469
+					                      if (convData[m]['status'].indexOf("delivered") > -1 || convData[m]['status'].indexOf("delivery success") > -1 || convData[m]['status'].indexOf("Retrieved") > -1) {
1470
+					                          var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
1471
+					                      } else {
1472
+					                          var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
1473
+					                      }
1474
+					                  } else {
1475
+					                      var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
1476
+					                  }
1477
+					                  rowMessageArrAdd.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent to current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:inline-block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
1478
+
1479
+					              } else if (convData[m]['direction'] == 'received_from') {
1480
+
1481
+							  rowMessageArrAdd.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div></div>");
1482
+
1483
+					              } else if (convData[m]['direction'] == 'received_on') {
1484
+
1485
+							  rowMessageArrAdd.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received on current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div></div>");
1486
+					              }
1487
+		                                 }
1488
+
1489
+					         var convDataPerNmbrad = rowMessageArrAdd.join("");
1490
+
1491
+		                                 var scrlheight = $("#msgListRowCell").height();
1492
+		                                 $("#msgListRowCell").prepend(convDataPerNmbrad);
1493
+
1494
+		                                 $("#frmMsgLstWrap").scrollTop($("#msgListRowCell").height() - scrlheight);
1495
+		                             });
1496
+
1497
+
1498
+					     // Show the messages sent by each user whose name is clicked
1499
+					     $('[id*="diplNm_"]').click(function() {
1500
+
1501
+					         var crntNmbr = $(this).attr("id").split("_")[1];
1502
+					         var crntDisName = $(this).attr("name");
1503
+		                                 $("#loadMoreMsgs").css("display", "none");
1504
+
1505
+		                                 var convDataprn = [];
1506
+		                                 $.each(msgsNmbrsNames[crntNmbr][crntDisName], function(index, item) {
1507
+		                                        convDataprn.push(item);
1508
+		                                 });
1509
+
1510
+		                                 // If the total number of messages is greater than the default number of messages to display, show the 'Load more messages' button
1511
+		                                 if (convDataprn.length > nmbTblDefault) {
1512
+		                                     $("#loadMoreMsgsusr").css("display", "block");
1513
+		                                     var nmbToBeLoaded = nmbTblDefault;
1514
+		                                 } else {
1515
+		                                     $("#loadMoreMsgsusr").css("display", "none");
1516
+		                                     var nmbToBeLoaded = convDataprn.length;
1517
+		                                 }
1518
+
1519
+					         var rowMessageArrprnst = [];
1520
+
1521
+					         for (var n = nmbToBeLoaded - 1; n >= 0; n--) {
1522
+		                                      rowMessageArrprnst.push(convDataprn[n]);
1523
+					         }
1524
+
1525
+					         var convDataPerNmbrprnst = rowMessageArrprnst.join("");
1526
+
1527
+		                                 $("#msgListRowCell").empty();
1528
+		                                 $("#msgListRowCell").append(convDataPerNmbrprnst);
1529
+
1530
+		                                 // Scroll down to the bottom of the window
1531
+		                                 $("#frmMsgLstWrap").animate({scrollTop:$("#frmMsgLstTbl").prop("scrollHeight")},200);
1532
+
1533
+		                                 // Load more messages
1534
+		                                 var clckNb = 0;
1535
+		                                 $("#loadMoreMsgsusr").unbind("click");
1536
+		                                 $("#loadMoreMsgsusr").click(function() {
1537
+
1538
+		                                     clckNb++;
1539
+		                                     var crefnb = (clckNb + 1) * nmbToBeLoaded;
1540
+
1541
+		                                     $("#loadMoreMsgs").css("display", "none");
1542
+
1543
+		                                     if (crefnb > convDataprn.length) {
1544
+		                                         var nmbmsg = convDataprn.length - 1;
1545
+		                                         $("#loadMoreMsgsusr").css("display", "none");
1546
+		                                     } else { 
1547
+		                                         var nmbmsg = crefnb - 1;
1548
+		                                         $("#loadMoreMsgsusr").css("display", "block");
1549
+		                                     }
1550
+
1551
+		                                     var rowMessageArrAddst = [];
1552
+
1553
+		                                     for (var q = nmbmsg; q >= clckNb * nmbToBeLoaded; q--) {
1554
+
1555
+		                                          rowMessageArrAddst.push(convDataprn[q]);
1556
+		                                     }
1557
+
1558
+					             var convDataPerNmbradst = rowMessageArrAddst.join("");
1559
+
1560
+		                                     var scrlheight = $("#msgListRowCell").height();
1561
+		                                     $("#msgListRowCell").prepend(convDataPerNmbradst);
1562
+
1563
+		                                     $("#frmMsgLstWrap").scrollTop($("#msgListRowCell").height() - scrlheight);
1564
+		                                 });
1565
+
1566
+					         $(".dispNameList").each(function() { $(this).css("color", "#0a559e"); });
1567
+					         $("#diplNmAllMsg").css("color", "#04957b");
1568
+					         $(this).css("color", "#1b8efe");
1569
+					     });
1570
+
1571
+
1572
+					     // Show again all the messages sent/received to/from the clicked number
1573
+					     $("#diplNmAllMsg").click(function() {
1574
+
1575
+		                                 $("#loadMoreMsgsusr").css("display", "none");
1576
+
1577
+		                                 var convDataprn = [];
1578
+		                                 $.each(messagesPerNmbr[clckPhNumber], function(index, item) {
1579
+		                                        convDataprn.push(item);
1580
+		                                 });
1581
+
1582
+
1583
+		                                 // If the total number of messages is greater than the default number of messages to display, show the 'Load more messages' button
1584
+		                                 if (convDataprn.length > nmbTblDefault) {
1585
+		                                     $("#loadMoreMsgs").css("display", "block");
1586
+		                                     var nmbToBeLoaded = nmbTblDefault;
1587
+		                                 } else {
1588
+		                                     $("#loadMoreMsgs").css("display", "none");
1589
+		                                     var nmbToBeLoaded = convDataprn.length;
1590
+		                                 }
1591
+
1592
+					         var rowMessageArrprnst = [];
1593
+
1594
+					         for (var n = nmbToBeLoaded - 1; n >= 0; n--) {
1595
+		                                      rowMessageArrprnst.push(convDataprn[n]);
1596
+					         }
1597
+
1598
+					         var convDataPerNmbrprnst = rowMessageArrprnst.join("");
1599
+
1600
+		                                 $("#msgListRowCell").empty();
1601
+		                                 $("#msgListRowCell").append(convDataPerNmbrprnst);
1602
+
1603
+		                                 // Scroll down to the bottom of the window
1604
+		                                 $("#frmMsgLstWrap").animate({scrollTop:$("#frmMsgLstTbl").prop("scrollHeight")},200);
1605
+
1606
+
1607
+		                                 // Load more messages
1608
+		                                 var clckNb = 0;
1609
+		                                 $("#loadMoreMsgs").unbind("click");
1610
+		                                 $("#loadMoreMsgs").click(function() {
1611
+
1612
+		                                     clckNb++;
1613
+		                                     var crefnb = (clckNb + 1) * nmbToBeLoaded;
1614
+
1615
+		                                     $("#loadMoreMsgsusr").css("display", "none");
1616
+
1617
+		                                     if (crefnb > convDataprn.length) {
1618
+		                                         var nmbmsg = convDataprn.length - 1;
1619
+		                                         $("#loadMoreMsgs").css("display", "none");
1620
+		                                     } else { 
1621
+		                                         var nmbmsg = crefnb - 1;
1622
+		                                         $("#loadMoreMsgs").css("display", "block");
1623
+		                                     }
1624
+
1625
+		                                     var rowMessageArrAddst = [];
1626
+
1627
+		                                     for (var q = nmbmsg; q >= clckNb * nmbToBeLoaded; q--) {
1628
+
1629
+		                                          rowMessageArrAddst.push(convDataprn[q]);
1630
+		                                     }
1631
+
1632
+					             var convDataPerNmbradst = rowMessageArrAddst.join("");
1633
+
1634
+		                                     var scrlheight = $("#msgListRowCell").height();
1635
+		                                     $("#msgListRowCell").prepend(convDataPerNmbradst);
1636
+
1637
+		                                     $("#frmMsgLstWrap").scrollTop($("#msgListRowCell").height() - scrlheight);
1638
+		                                 });
1639
+
1640
+
1641
+					         $(".dispNameList").each(function() { $(this).css("color", "#0a559e"); });
1642
+					         $("#diplNmAllMsg").css("color", "#04957b");
1643
+					         $(this).css("color", "#04c6a4");
1644
+
1645
+					     });
1646
+
1647
+
1648
+					     // Show the scroll-up arrow
1649
+					     $("#frmMsgLstWrap").scroll(function() {
1650
+						if ($(this).scrollTop() > 900) {
1651
+						      $('#upArrowSmall').fadeIn();
1652
+						} else {
1653
+						      $('#upArrowSmall').fadeOut();
1654
+						}
1655
+					     });
1656
+
1657
+					     $("#upArrowSmall").click(function() {
1658
+						$("#frmMsgLstWrap").animate({scrollTop : 0},400);
1659
+					     });
1660
+
1661
+
1662
+					     // Download MMS files when clicking on their URLs
1663
+					     $('[id^="mmsTblUrl-"]').on('click', function(evt) {
1664
+
1665
+					        var clckedUrl = $(this).text();
1666
+					        var flNamearr = clckedUrl.split("/");
1667
+					        var flName = flNamearr.reverse()[0];
1668
+
1669
+					        confirmAlert("Download this file only if you trust the sender and the domain of the URL.");
1670
+
1671
+					        $("#confirmOk").click(function() {
1672
+
1673
+					           $("#alertMsgOverlay").remove();
1674
+					           $("#alertConfMessage").remove();
1675
+
1676
+					           var mmsLink = document.createElement("a");
1677
+					           mmsLink.setAttribute('href', clckedUrl);
1678
+					           mmsLink.setAttribute('download', flName);
1679
+                                                   mmsLink.setAttribute('target', '_blank');
1680
+					           document.body.appendChild(mmsLink);
1681
+					           mmsLink.click();
1682
+					           mmsLink.remove();
1683
+					        });
1684
+
1685
+					        $("#confirmCancel").click(function() { $("#alertMsgOverlay").remove(); $("#alertConfMessage").remove(); });
1686
+					     });
1687
+
1688
+				  },
1689
+				  error: function() {
1690
+		                             showAlert("Error while attempting to get message data from the database!");
1691
+					     $('#listAllMsgsFromTo').removeClass('icon-loading');
1692
+				  }
1693
+			   });
1694
+
1695
+                           // Scroll down to the bottom of the window
1696
+                           $("#frmMsgLstWrap").animate({scrollTop:$("#frmMsgLstTbl").prop("scrollHeight")},200);
1697
+                   }
1698
+
1699
+                   getMsgsPerNmbr(clckPhNumber);
1700
+
1701
+                   $("#refreshMsgsConvtf").click(function() { getMsgsPerNmbr(clckPhNumber); setTimeout(function() { $("#diplNmAllMsg").click(); }, 1000); });
1702
+                }
1703
+
1704
+                $('[id^="showMsgFrom-"]').click(function() {
1705
+
1706
+                   var ctrwnb = $(this).attr("id").replace("showMsgFrom-", "");
1707
+                   var clckPhNumber = $("#frmNmbr-"+ ctrwnb).text();
1708
+
1709
+                   showMsgPerNmbr(clckPhNumber);
1710
+                })
1711
+
1712
+                $('[id^="showMsgTo-"]').click(function() {
1713
+                   var ctrwnbTo = $(this).attr("id").replace("showMsgTo-", "");
1714
+                   if ($("#toNmbr-"+ ctrwnbTo).text().indexOf(":") > -1) {
1715
+                       var clckPhNbTo = $("#toNmbr-"+ ctrwnbTo).text().split(": ")[1];
1716
+                   } else { var clckPhNbTo = $("#toNmbr-"+ ctrwnbTo).text(); };
1717
+
1718
+                   showMsgPerNmbr(clckPhNbTo);
1719
+                })
1720
+
1721
+                // Show the pop-up window for adding a Display Name to the 'From' numbers of unknown senders
1722
+                $('[id^="addDispName-"]').click(function() {
1723
+
1724
+                   var crrownb = $(this).attr("id").replace("addDispName-", "");
1725
+                   var slctPhoneNb = $("#frmNmbr-"+ crrownb).text();
1726
+
1727
+                   var addDNameWindow = "<div id='disNameWindow'>";
1728
+                   addDNameWindow += "<div id='dragDispNmWindow'><img src='/" + ctappdir + "/sms_relentless/img/dots.svg'></div>";
1729
+                   addDNameWindow += "<a id='closeDisNmWindow' title='Close this window'></a>";
1730
+                   addDNameWindow += "<div style='display:block;text-align:left;margin:14px 22px 0px 22px;color:#353535;font-family:Inter;font-size:15px;font-weight:400;'>If this is an external phone number (the number of a person that doesn't have a Nextcloud account), you can save a Display Name for this number, so that all the messages coming from it will be preceded by the specified Display Name:</div>";
1731
+                   addDNameWindow += "<div style='display:block;text-align:center;color:#49B382;font-family:Inter;font-size:15px;font-weight:600;margin:6px 0px 10px 0px;'>"+ slctPhoneNb +"</div>";
1732
+                   addDNameWindow += "<input type='text' id='saveDispNmText' placeholder='Eg: John Smith' style='display:block;width:80%;height:30px;margin:10px auto;padding:0px 12px;border-radius: 20px;'>";
1733
+                   addDNameWindow += "<input type='submit' id='saveDispName' value='Save'>";
1734
+                   addDNameWindow += "</div>";
1735
+
1736
+                   $("#content").append("<div id='recTblOverlay'></div>");
1737
+                   $("#content").append(addDNameWindow);
1738
+
1739
+                   var topNmDist = parseInt((window.innerHeight / 2).toFixed(2) - 180) +"px";
1740
+                   var leftNmDist = parseInt((window.innerWidth / 2).toFixed(2) - 150) +"px";
1741
+                   $("#disNameWindow").css({ "top" : topNmDist, "left" : leftNmDist });
1742
+
1743
+                   $("#closeDisNmWindow").click(function() { $("#disNameWindow").remove(); $("#recTblOverlay").remove(); });
1744
+                   $("#recTblOverlay").click(function() { $("#disNameWindow").remove(); $("#recTblOverlay").remove(); });
1745
+
1746
+
1747
+	           // Make the window draggable
1748
+	           function makeMgrWndDraggable(e) {
1749
+
1750
+			   window.pmdragging = {};
1751
+			   pmdragging.pageX0 = e.pageX;
1752
+			   pmdragging.pageY0 = e.pageY;
1753
+			   pmdragging.elem = $("#disNameWindow");
1754
+			   pmdragging.offset0 = $("#disNameWindow").offset();
1755
+
1756
+			   function handle_dragging(e) {
1757
+			       var left = pmdragging.offset0.left + (e.pageX - pmdragging.pageX0);
1758
+			       var top = pmdragging.offset0.top + (e.pageY - pmdragging.pageY0);
1759
+			       $(pmdragging.elem).offset({top: top, left: left});
1760
+			   }
1761
+
1762
+			   function handle_mouseup(e) {
1763
+			       $('body').off('mousemove', handle_dragging).off('mouseup', handle_mouseup);
1764
+			   }
1765
+
1766
+			   $('body').on('mouseup', handle_mouseup).on('mousemove', handle_dragging);
1767
+	           }
1768
+	           $("#dragDispNmWindow").mousedown(makeMgrWndDraggable);
1769
+
1770
+                   // Save the Display Name
1771
+                   $("#saveDispName").click(function() {
1772
+
1773
+                      var dispNmText = $("#saveDispNmText").val();
1774
+
1775
+                      if (/^[a-zA-Z0-9\s\-\/\.\)\(\']+$/.test(dispNmText) && dispNmText.length < 256) {
1776
+
1777
+                             var saveDispNameUrl = OC.generateUrl("/apps/sms_relentless/user/savedisplayname");
1778
+
1779
+			     $.ajax({
1780
+				  url: saveDispNameUrl + '/' + userid,
1781
+				  method: 'POST',
1782
+				  dataType:'text',
1783
+                                  data: { 
1784
+                                          authorDisplayname: dispNmText,
1785
+                                          from: slctPhoneNb
1786
+                                         },
1787
+				  success: function(respupdname) {
1788
+                                               showAlert(respupdname);
1789
+                                               $("#disNameWindow").remove();
1790
+                                               $("#recTblOverlay").remove();
1791
+                                  },
1792
+				  error: function() {
1793
+                                               showAlert("Error while attempting to save the new Display Name to the database.");
1794
+                                               $("#disNameWindow").remove();
1795
+                                               $("#recTblOverlay").remove();
1796
+                                  }
1797
+			     });
1798
+
1799
+                      } else {
1800
+                              showAlert("The Display Name should contain only letters, numbers, spaces, hyphens (-), slashes (/), periods (.), round brackets ()() and single quotation marks ('), it should not be empty and should have less than 256 characters.");
1801
+                      }
1802
+                   });
1803
+
1804
+                });
1805
+
1806
+
1807
+                // Add pagination
1808
+                var rowsShown = messagesperpage;
1809
+                var rowsTotal = $("#recSmsTable tr").length;
1810
+
1811
+                var numPages = (rowsTotal - 2) / rowsShown;
1812
+
1813
+                for (i = 0; i < numPages; i++) {
1814
+                     var pageNum = i + 1;
1815
+                     $('#paginationrec').append('<a href="#" rel="' + i + '" class="pagenumbersrec">' + pageNum + '</a> ');
1816
+                }
1817
+
1818
+                $('#paginationrec').children(":first").addClass('active');
1819
+
1820
+                $('#paginationrec a:first').addClass('active');
1821
+
1822
+                // Show table page when clicking a page number
1823
+                $('.recpages a').bind('click', function() {
1824
+
1825
+                   $('#paginationrec').children().removeClass('active');
1826
+
1827
+                   $(this).addClass('active');
1828
+
1829
+                   var currentPageNo = $(this).text();
1830
+
1831
+                   $('#paginationrec a').each(function() {
1832
+                       if ($(this).text() == currentPageNo) {
1833
+                           $(this).addClass('active');
1834
+                       }
1835
+                   });
1836
+
1837
+                   // Sort table rows
1838
+		   var rows = $('#recSmsTable tr').get();
1839
+
1840
+		   rows.sort(function(a, b) {
1841
+
1842
+		        var A = parseInt($('td.dbidcolumnrec', a).text());
1843
+		        var B = parseInt($('td.dbidcolumnrec', b).text());
1844
+
1845
+		        if (A < B) {
1846
+		            return -1;
1847
+		        }
1848
+
1849
+		        if (A > B) {
1850
+		            return 1;
1851
+		        }
1852
+
1853
+		        return 0;
1854
+		   });
1855
+
1856
+		   $.each(rows, function(index, row) {
1857
+		      $('#recSmsTable').append(row);
1858
+		   });
1859
+
1860
+                   var currPage = $(this).attr('rel');
1861
+                   var startItem = currPage * rowsShown;
1862
+                   var endItem = startItem + rowsShown;
1863
+
1864
+                   $(".receivedrowsbody").hide().slice(startItem, endItem).css('display', 'table-row');
1865
+
1866
+                   $('#totalrecmessages').remove();
1867
+                   $('#smstables').append("<div id='totalrecmessages'>Total displayed messages: " + parseddata.length + "</div>");
1868
+                });
1869
+
1870
+                $('#paginationrec').children(":last").trigger('click');
1871
+
1872
+                // Select all records
1873
+                $('#selectAllChckbx').change(function() {
1874
+                  if ($(this).is(':checked')) {
1875
+                       $(".indivchckbx").prop("checked", true);
1876
+                  } else {
1877
+                       $(".indivchckbx").prop("checked", false);
1878
+                  }
1879
+                });
1880
+
1881
+                function reorderRecRows() {
1882
+                   var currenttext = $(".filterbuttonsrec").closest('[class="filterbuttonsrec"]').find('[class="indivfilterrec"]').text();
1883
+                   if (currenttext == '') {
1884
+                       $('tr').sort(function (a, b) {
1885
+                          return parseInt($('td.dbidcolumnrec', b).text()) < parseInt($('td.dbidcolumnrec', a).text());
1886
+                       }).appendTo("#recSmsTable");
1887
+                   }
1888
+                }
1889
+
1890
+                // Filter rows
1891
+                $("#databaseidfilter").on("click", function(event) {
1892
+
1893
+                      var databaseId = $("#dbidtextrec").val();
1894
+                      var msgrowsNo = 0;
1895
+
1896
+                      $(".receivedrowsbody").each(function() {
1897
+
1898
+                          var checkrecEmpty1 = 0;
1899
+                          $(".indivfilterrec").not("#dbidtextrec").each(function() {
1900
+                              if ($(this).val() != '') {
1901
+                                  checkrecEmpty1 = 1;
1902
+                              }
1903
+                          });
1904
+
1905
+                          if (checkrecEmpty1 == 0) {
1906
+                              $(this).show();
1907
+                          }
1908
+
1909
+                          if (databaseId != '') {
1910
+                             if ($(this).find('[class="dbidcolumnrec"]').text() == databaseId) {
1911
+                                $("#recSmsTable").append(this);
1912
+                                if ($(this).is(":visible")) { msgrowsNo++; }
1913
+                             } else {
1914
+                                $(this).hide();
1915
+                             }
1916
+                          } else {
1917
+                                $(this).show();
1918
+                                msgrowsNo++;
1919
+                          }
1920
+                      });
1921
+
1922
+                      reorderRecRows();
1923
+                      $('#totalrecmessages').remove();
1924
+                      $('#smstables').append("<div id='totalrecmessages'>Total filtered messages: " + msgrowsNo + "</div>");
1925
+                });
1926
+
1927
+
1928
+                $("#useridfilter").on("click", function(event) {
1929
+
1930
+                      var useridtxt = $("#useridtextrec").val().toLowerCase();
1931
+                      var msgrowsNo = 0;
1932
+
1933
+                      $(".receivedrowsbody").each(function() {
1934
+
1935
+                          var checkrecEmpty2 = 0;
1936
+                          $(".indivfilterrec").not("#useridtextrec").each(function() {
1937
+                              if ($(this).val() != '') {
1938
+                                  checkrecEmpty2 = 1;
1939
+                              }
1940
+                          });
1941
+
1942
+                          if (checkrecEmpty2 == 0) {
1943
+                              $(this).show();
1944
+                          }
1945
+
1946
+                          if (useridtxt != '') {
1947
+                             var useridfound = $(this).find('[class="useridcolrec"]').text().toLowerCase();
1948
+                             if(useridfound.indexOf(useridtxt) != -1) {
1949
+                                $("#recSmsTable").append(this);
1950
+                                if ($(this).is(":visible")) { msgrowsNo++; }
1951
+                             } else {
1952
+                                $(this).hide();
1953
+                             }
1954
+                          } else {
1955
+                                $(this).show();
1956
+                                msgrowsNo++;
1957
+                          }
1958
+                      });
1959
+
1960
+                      reorderRecRows();
1961
+                      $('#totalrecmessages').remove();
1962
+                      $('#smstables').append("<div id='totalrecmessages'>Total filtered messages: " + msgrowsNo + "</div>");
1963
+                });
1964
+
1965
+                $("#messageidfilter").on("click", function(event) {
1966
+
1967
+                      var messageidtxt = $("#messageidtextrec").val().toLowerCase();
1968
+                      var msgrowsNo = 0;
1969
+
1970
+                      $(".receivedrowsbody").each(function() {
1971
+
1972
+                          var checkrecEmpty3 = 0;
1973
+                          $(".indivfilterrec").not("#messageidtextrec").each(function() {
1974
+                              if ($(this).val() != '') {
1975
+                                  checkrecEmpty3 = 1;
1976
+                              }
1977
+                          });
1978
+
1979
+                          if (checkrecEmpty3 == 0) {
1980
+                              $(this).show();
1981
+                          }
1982
+
1983
+                          if (messageidtxt != '') {
1984
+                             var foundtdmssgid = $(this).find('[class="messageidcolrec"]').text().toLowerCase();
1985
+                             if (foundtdmssgid.indexOf(messageidtxt) != -1) {
1986
+                                $("#recSmsTable").append(this);
1987
+                                if ($(this).is(":visible")) { msgrowsNo++; }
1988
+                             } else {
1989
+                                $(this).hide();
1990
+                             }
1991
+                          } else {
1992
+                                $(this).show();
1993
+                                msgrowsNo++;
1994
+                          }
1995
+                      });
1996
+
1997
+                      reorderRecRows();
1998
+                      $('#totalrecmessages').remove();
1999
+                      $('#smstables').append("<div id='totalrecmessages'>Total filtered messages: " + msgrowsNo + "</div>");
2000
+                });
2001
+
2002
+                $("#datefilter").on("click", function(event) {
2003
+
2004
+                      var datetxtvr = $("#datetextrec").val().toLowerCase();
2005
+                      var msgrowsNo = 0;
2006
+
2007
+                      $(".receivedrowsbody").each(function() {
2008
+
2009
+                          var checkrecEmpty4 = 0;
2010
+                          $(".indivfilterrec").not("#datetextrec").each(function() {
2011
+                              if ($(this).val() != '') {
2012
+                                  checkrecEmpty4 = 1;
2013
+                              }
2014
+                          });
2015
+
2016
+                          if (checkrecEmpty4 == 0) {
2017
+                              $(this).show();
2018
+                          }
2019
+
2020
+                          if (datetxtvr != '') {
2021
+                              var founddate = $(this).find('[class="datecolrec"]').text().toLowerCase();
2022
+                              if (founddate.indexOf(datetxtvr) != -1) {
2023
+                                  $("#recSmsTable").append(this);
2024
+                                  if ($(this).is(":visible")) { msgrowsNo++; }
2025
+                              } else {
2026
+                                  $(this).hide();
2027
+                              }
2028
+                          } else {
2029
+                                  $(this).show();
2030
+                                  msgrowsNo++;
2031
+                          }
2032
+                      });
2033
+
2034
+                      reorderRecRows();
2035
+                      $('#totalrecmessages').remove();
2036
+                      $('#smstables').append("<div id='totalrecmessages'>Total filtered messages: " + msgrowsNo + "</div>");
2037
+                });
2038
+
2039
+                $("#fromfilter").on("click", function(event) {
2040
+
2041
+                      var fromtxtvr = $("#fromtextrec").val().toLowerCase();
2042
+                      var msgrowsNo = 0;
2043
+
2044
+                      $(".receivedrowsbody").each(function() {
2045
+
2046
+                          var checkrecEmpty5 = 0;
2047
+                          $(".indivfilterrec").not("#fromtextrec").each(function() {
2048
+                              if ($(this).val() != '') {
2049
+                                  checkrecEmpty5 = 1;
2050
+                              }
2051
+                          });
2052
+
2053
+                          if (checkrecEmpty5 == 0) {
2054
+                              $(this).show();
2055
+                          }
2056
+
2057
+                          if (fromtxtvr != '') {
2058
+                             var foundfrom = $(this).find('[class="fromcolumnrec"]').text().toLowerCase();
2059
+                             if (foundfrom.indexOf(fromtxtvr) != -1) {
2060
+                                 $("#recSmsTable").append(this);
2061
+                                 if ($(this).is(":visible")) { msgrowsNo++; }
2062
+                             } else {
2063
+                                 $(this).hide();
2064
+                             }
2065
+                          } else {
2066
+                                 $(this).show();
2067
+                                 msgrowsNo++;
2068
+                          }
2069
+                      });
2070
+
2071
+                      reorderRecRows();
2072
+                      $('#totalrecmessages').remove();
2073
+                      $('#smstables').append("<div id='totalrecmessages'>Total filtered messages: " + msgrowsNo + "</div>");
2074
+                });
2075
+
2076
+                $("#tofilter").on("click", function(event) {
2077
+
2078
+                      var totxtvr = $("#totextrec").val().toLowerCase();
2079
+                      var msgrowsNo = 0;
2080
+
2081
+                      $(".receivedrowsbody").each(function() {
2082
+
2083
+                          var checkrecEmpty6 = 0;
2084
+                          $(".indivfilterrec").not("#totextrec").each(function() {
2085
+                              if ($(this).val() != '') {
2086
+                                  checkrecEmpty6 = 1;
2087
+                              }
2088
+                          });
2089
+
2090
+                          if (checkrecEmpty6 == 0) {
2091
+                              $(this).show();
2092
+                          }
2093
+
2094
+                          if (totxtvr != '') {
2095
+                             var foundto = $(this).find('[class="tocolrec"]').text().toLowerCase();
2096
+                             if (foundto.indexOf(totxtvr) != -1) {
2097
+                                 $("#recSmsTable").append(this);
2098
+                                 if ($(this).is(":visible")) { msgrowsNo++; }
2099
+                             } else {
2100
+                                 $(this).hide();
2101
+                             }
2102
+                          } else {
2103
+                                 $(this).show();
2104
+                                 msgrowsNo++;
2105
+                          }
2106
+                      });
2107
+
2108
+                      reorderRecRows();
2109
+                      $('#totalrecmessages').remove();
2110
+                      $('#smstables').append("<div id='totalrecmessages'>Total filtered messages: " + msgrowsNo + "</div>");
2111
+                });
2112
+
2113
+                $("#messagefilter").on("click", function(event) {
2114
+
2115
+                      var messagetxtvr = $("#messagetextrec").val().toLowerCase();
2116
+                      var msgrowsNo = 0;
2117
+
2118
+                      $(".receivedrowsbody").each(function() {
2119
+
2120
+                          var checkrecEmpty7 = 0;
2121
+                          $(".indivfilterrec").not("#messagetextrec").each(function() {
2122
+                              if ($(this).val() != '') {
2123
+                                  checkrecEmpty7 = 1;
2124
+                              }
2125
+                          });
2126
+
2127
+                          if (checkrecEmpty7 == 0) {
2128
+                              $(this).show();
2129
+                          }
2130
+
2131
+                          if (messagetxtvr != '') {
2132
+                             var foundmessage = $(this).find('[class="messagecolumnrec"]').text().toLowerCase();
2133
+                             if (foundmessage.indexOf(messagetxtvr) != -1) {
2134
+                                $("#recSmsTable").append(this);
2135
+                                if ($(this).is(":visible")) { msgrowsNo++; }
2136
+                             } else {
2137
+                                $(this).hide();
2138
+                             }
2139
+                          } else {
2140
+                                $(this).show();
2141
+                                msgrowsNo++;
2142
+                          }
2143
+                      });
2144
+
2145
+                      reorderRecRows();
2146
+                      $('#totalrecmessages').remove();
2147
+                      $('#smstables').append("<div id='totalrecmessages'>Total filtered messages: " + msgrowsNo + "</div>");
2148
+               });
2149
+
2150
+               // Clear all filters
2151
+               $("#clearrecfilters").on("click", function(event) {
2152
+                      $(".receivedrowsbody").each(function() {
2153
+                          $(this).show();
2154
+                      });
2155
+                      $(".indivfilterrec").val("");
2156
+                      $('#totalrecmessages').remove();
2157
+                      $('#smstables').append("<div id='totalrecmessages'>Total displayed messages: " + parseddata.length + "</div>");
2158
+               });
2159
+
2160
+               // Delete selected rows from the database
2161
+               $("#deleterecrows").on("click", function() {
2162
+                  var checkcheckbx = jQuery("#recSmsTable input[type=checkbox]:checked").length;
2163
+                  if (checkcheckbx == 0) {
2164
+                      showAlert("Please select the row(s) to permanently delete from the database !");
2165
+                  } else {
2166
+                          var checkboxIds = [];
2167
+                          $(".receivedrowsbody").each(function() {
2168
+                             var rowcheckbx = $(this).find('input[type="checkbox"]');
2169
+                             if (rowcheckbx.is(":checked")) {
2170
+                                 var dbrowid = $(this).find('[class="dbidcolumnrec"]').text();
2171
+                                 checkboxIds.push(dbrowid);
2172
+                             }
2173
+                          });
2174
+
2175
+		          confirmAlert("Please note that the row(s) you selected will be permanently deleted from the database, without being saved before removal. This action cannot be undone ! If you really want to permanently delete the selected row(s) press 'OK'.");
2176
+
2177
+		          $("#confirmCancel").click(function() { $("#alertMsgOverlay").remove(); $("#alertConfMessage").remove(); });
2178
+
2179
+		          $("#confirmOk").click(function() {
2180
+
2181
+		              $("#alertMsgOverlay").remove();
2182
+		              $("#alertConfMessage").remove();
2183
+
2184
+                              var deleterecRowsUrl = OC.generateUrl("/apps/sms_relentless/user/removerecrows");
2185
+                              $('#smstables').addClass('icon-loading');
2186
+
2187
+                              $.ajax({
2188
+                                   url: deleterecRowsUrl + '/' + userid,
2189
+                                   method: "POST",
2190
+                                   dataType:'text',
2191
+                                   data: {recmessagedbIDs: checkboxIds},
2192
+                                   success: function() {
2193
+                                              showAlert("The row(s) have been deleted successfully !");
2194
+                                              $('#smstables').removeClass('icon-loading');
2195
+                                              $('#receivedsmstableshow').click();
2196
+                                   },
2197
+                                   error: function() {
2198
+                                              showAlert("There was an error while deleting the selected row(s) !");
2199
+                                              $('#smstables').removeClass('icon-loading');
2200
+                                   }
2201
+                              });
2202
+                          });
2203
+
2204
+                  }
2205
+               });
2206
+
2207
+
2208
+               // Show/Hide filter row
2209
+	       $('#recarrow').on('click', function() {
2210
+	          if ($('#recfiltersrow').is(':visible')) {
2211
+		      $('#recfiltersrow').hide();
2212
+                      $('#recheaderrow').css('top', '0px');
2213
+                      $(this).removeClass('arrowUpCl');
2214
+                      $(this).addClass('arrowDownCl');
2215
+		  } else {
2216
+		      $('#recfiltersrow').show();
2217
+                      $('#recheaderrow').css('top', '158px');
2218
+                      $(this).removeClass('arrowDownCl');
2219
+                      $(this).addClass('arrowUpCl');
2220
+                  }
2221
+               });
2222
+
2223
+               $("#app-content").animate({scrollTop:$("#recSmsTable").prop("scrollHeight")},200);
2224
+
2225
+
2226
+               // Download MMS files when clicking on their URLs
2227
+               $('[id^="mmsTblUrl-"]').on('click', function(evt) {
2228
+
2229
+                  var clckedUrl = $(this).text();
2230
+                  var flNamearr = clckedUrl.split("/");
2231
+                  var flName = flNamearr.reverse()[0];
2232
+
2233
+                  confirmAlert("Download this file only if you trust the sender and the domain of the URL.");
2234
+
2235
+		  $("#confirmOk").click(function() {
2236
+
2237
+                     $("#alertMsgOverlay").remove();
2238
+		     $("#alertConfMessage").remove();
2239
+
2240
+		     var mmsLink = document.createElement("a");
2241
+		     mmsLink.setAttribute('href', clckedUrl);
2242
+		     mmsLink.setAttribute('download', flName);
2243
+		     mmsLink.setAttribute('target', '_blank');
2244
+		     document.body.appendChild(mmsLink);
2245
+		     mmsLink.click();
2246
+		     mmsLink.remove();
2247
+                  });
2248
+
2249
+		  $("#confirmCancel").click(function() { $("#alertMsgOverlay").remove(); $("#alertConfMessage").remove(); });
2250
+               });
2251
+
2252
+          },
2253
+          error: function(recdatafromdb) {
2254
+                      showAlert("Error. You can check the Nextcloud log to find more details about this issue.");
2255
+                      $('#smstables').removeClass('icon-loading');
2256
+          }
2257
+     });
2258
+
2259
+     // Look for the 'new received message' indicator in the database, to know if the received messages list needs to be refreshed
2260
+     intervalNmfr = setInterval(function() { checkIfNewMessage(); }, newMsgInterval);
2261
+
2262
+     // Show the auto-refresh button
2263
+     if ($("#stopAutoRefreshSentBtn").text() == "Stop auto refresh") {
2264
+         $("#stopAutoRefreshSentBtn").click();
2265
+     }
2266
+
2267
+     $("#stopAutoRefreshSent").css("display", "none");
2268
+
2269
+  });
2270
+
2271
+
2272
+  // List sent messages
2273
+  $("#sentsmstableshow").on("click", function(event) {
2274
+
2275
+     $('#smstables').empty();
2276
+     clearInterval(intervalNmfr);
2277
+
2278
+     var getSentUrl = OC.generateUrl("/apps/sms_relentless/user/getsenttable");
2279
+     $('#smstables').addClass('icon-loading');
2280
+
2281
+     $.ajax({
2282
+          url: getSentUrl + '/' + userid,
2283
+          method: "GET",
2284
+          contentType: 'application/json',
2285
+          success: function(sentdatafdb) {
2286
+
2287
+                var sentparseddata = sentdatafdb.datarows;
2288
+
2289
+                $('#smstables').append("<div id='toptablesent'><div class='topbuttonandpage'><span id='sentarrow' title='Show/Hide filters and Delete button'></span></div><div id='paginationsent' class='pages'>Pages </div></div>");
2290
+                $('#smstables').append("<table id='sentSmsTable'></table>");
2291
+                $('#sentSmsTable').append("<tr id='sentfiltersrow'><td class='selectalldvfilter'><button id='clearsentfilters' title='Clear all filters.'></button><button id='deletesentrows' title='Permanently delete the selected row(s) from below from the database.'></button></td><td class='selectalldvfilter'><input type='text' id='dbidtextsent' class='indivfiltersent' title='Enter a database ID number to apply the filter.'><input type='submit' id='databaseidfilter' class='filterbuttonsent' value='' title='Filter rows by the specified database ID.' /></td><td class='selectalldvfilter'><input type='text' id='useridtext' class='indivfiltersent' title='Enter a Nextcloud username to apply the filter.' /><input type='submit' id='useridfilter' class='filterbuttonsent' value='' title='Filter rows by the specified username.' /></td><td class='selectalldvfilter'><input type='text' id='messageidtext' class='indivfiltersent' title='Enter a fragment from a message ID to apply the filter.'  /><input type='submit' id='messageidfilter' class='filterbuttonsent' value='' title='Filter rows by the specified string.' /></td><td class='selectalldvfilter'><input type='text' id='datetext' class='indivfiltersent' title='Enter a fragment of a date to apply the filter.'/><input type='submit' id='datefilter' class='filterbuttonsent' value='' title='Filter rows by the specified string.' /></td><td class='selectalldvfilter'><input type='text' id='fromtext' class='indivfiltersent' title='Enter a fragment of a sender&#146s phone number or alphanumeric Sender ID, to apply the filter.' /><input type='submit' id='fromfilter' class='filterbuttonsent' value='' title='Filter rows by the specified string.' /></td><td class='selectalldvfilter'><input type='text' id='totext' class='indivfiltersent' value='' title='Enter a fragment of a recipient&#146s phone number to apply the filter.'  /><input type='submit' id='tofilter' class='filterbuttonsent' value='' title='Filter rows by the specified string.' /></td><td class='selectalldvfilter'><input type='text' id='networktext' class='indivfiltersent' title='Enter a fragment of a network number to apply the filter.' /><input type='submit' id='networkfilter' class='filterbuttonsent' value='' title='Filter rows by the specified string.'/></td><td class='selectalldvfilter'><input type='text' id='pricetext' class='indivfiltersent' title='Enter a fragment of a price string to apply the filter.' /><input type='submit' id='pricefilter' class='filterbuttonsent' value='' title='Filter rows by the specified string.'/></td><td class='selectalldvfilter'><input type='text' id='statustext' class='indivfiltersent' title='Enter a fragment of a status to apply the filter.' /><input type='submit' id='statusfilter' class='filterbuttonsent' value='' title='Filter rows by the specified string.'/></td><td class='selectalldvfilter'><input type='text' id='deliveryrcpttext' class='indivfiltersent' title='Enter a fragment of a delivery receit to apply the filter.' /><input type='submit' id='deliveryrecfilter' class='filterbuttonsent' value='' title='Filter rows by the specified string.'/></td><td class='selectalldvfilter'><input type='text' id='messagetext' class='indivfiltersent' title='Enter a fragment of a message to apply the filter.' /><input type='submit' id='messagefilter' class='filterbuttonsent' value='' title='Filter rows by the specified string.'/></td></tr>");
2292
+                $('#sentSmsTable').append("<tr class='sentrows' id='sentheaderrow'><th id='selectalldv' class='selectsmsdv'><input type='checkbox' id='selectAllChckbx' class ='indivchckbx' title='Select all rows.' /></th><th title='The database ID of each message.'>ID</th><th>User ID</th><th>Message ID</th><th>Date</th><th>From</th><th>To</th><th title='When a 5 or 6 digits code appears in this column, the first 3 digits specify the mobile country code and the last 2 or 3 digits specify the mobile network code of the receiver. You can look up the mobile country code and then the mobile network code on https://en.wikipedia.org/wiki/Mobile_country_code#National_operators'>Network</th><th title=\"The currency is the currency configured in the client account, on the SMS provider's website.\">Price</th><th id='sentstatuscolumn' title=\"This column generally shows the status received from the recipient's carrier, or any errors generated when attempting to send the message.\">Status</th><th title='Not all delivery receipts guarantee that the target received the message. Some delivery receipts represent successful completion of just one step in the delivery process, such as transmitting the message to another telephony operator.'>Delivery<br>Receit</th><th>Sent Message</th></tr>");
2293
+
2294
+                $('#sentfiltersrow').hide();
2295
+
2296
+                if (sentdatafdb.showdispnm == 1) {
2297
+
2298
+                    for (var i = 0; i < sentparseddata.length; i++) {
2299
+
2300
+                         if (sentparseddata[i].author_displayname) {
2301
+                             var procmessage = "<span class='messageAuthorName'>"+ sentparseddata[i].author_displayname + ":</span>" + sentparseddata[i].message +"<div id='showMsgConv-"+ i +"' class='lstMsgConv'><img class='lstMsgConvImg' src='/" + ctappdir + "/sms_relentless/img/reply.svg' title='Show all the messages exchanged between the current 2 phone numbers.'></div>";
2302
+                         } else {
2303
+                             var procmessage = sentparseddata[i].message +"<div id='showMsgConv-"+ i +"' class='lstMsgConv'><img class='lstMsgConvImg' src='/" + ctappdir + "/sms_relentless/img/reply.svg' title='Show all the messages exchanged between the current 2 phone numbers.'></div>";
2304
+                         }
2305
+
2306
+                         var procsentFrom = "<div id='frmNmbr-"+ i +"'>"+ sentparseddata[i].from +"<div id='showMsgFrom-"+ i +"' class='listToFromMsgs'><img class='lstMsgToFromImg' src='/" + ctappdir + "/sms_relentless/img/list.svg' title='Show all the messages sent/received to/from this phone number, that I am allowed to see.'></div></div>";
2307
+
2308
+                         var procsentTo = "<div id='toNmbr-"+ i +"'>"+ sentparseddata[i].to +"<div id='showMsgTo-"+ i +"' class='listToFromMsgs'><img class='lstMsgToFromImg' src='/" + ctappdir + "/sms_relentless/img/list.svg' title='Show all the messages sent/received to/from this phone number, that I am allowed to see.'></div></div>";
2309
+
2310
+                         $('#sentSmsTable').append("<tr id='singlerow_"+ i +"' class='sentrowsbody'><td class='selectsmsdv'><input type='checkbox' id='selectspec_"+ i +"' class='indivchckbx' /></td><td class='sentdbidcolumn'>"+ sentparseddata[i].id +"</td><td class='useridcolsent'>"+ sentparseddata[i].user_id +"</td><td class='messageidcolsent'>"+ sentparseddata[i].message_id +"</td><td class='datecolsent'>"+ sentparseddata[i].date +"</td><td class='fromcolumnsent'>"+ procsentFrom +"</td><td class='tocolumnsent'>"+ procsentTo +"</td><td class='networkcolumnsent'>"+ sentparseddata[i].network +"</td><td class='pricecolumnsent'>"+ sentparseddata[i].price +"</td><td class='statuscolumnsent'>"+ sentparseddata[i].status +"</td><td class='deliveryrcptcolsent'>"+ sentparseddata[i].deliveryreceipt +"</td><td class='messagecolumnsent'>"+ procmessage +"</td></tr>");
2311
+                    }
2312
+
2313
+                } else {
2314
+
2315
+                    for (var i = 0; i < sentparseddata.length; i++) {
2316
+
2317
+                         var procmessage = sentparseddata[i].message +"<div id='showMsgConv-"+ i +"' class='lstMsgConv'><img class='lstMsgConvImg' src='/" + ctappdir + "/sms_relentless/img/reply.svg' title='Show all the messages exchanged between the current 2 phone numbers.'></div>";
2318
+
2319
+                         var procsentFrom = "<div id='frmNmbr-"+ i +"'>"+ sentparseddata[i].from +"<div id='showMsgFrom-"+ i +"' class='listToFromMsgs'><img class='lstMsgToFromImg' src='/" + ctappdir + "/sms_relentless/img/list.svg' title='Show all the messages sent/received to/from this phone number, that I am allowed to see.'></div></div>";
2320
+
2321
+                         var procsentTo = "<div id='toNmbr-"+ i +"'>"+ sentparseddata[i].to +"<div id='showMsgTo-"+ i +"' class='listToFromMsgs'><img class='lstMsgToFromImg' src='/" + ctappdir + "/sms_relentless/img/list.svg' title='Show all the messages sent/received to/from this phone number, that I am allowed to see.'></div></div>";
2322
+
2323
+                         $('#sentSmsTable').append("<tr id='singlerow_"+ i +"' class='sentrowsbody'><td class='selectsmsdv'><input type='checkbox' id='selectspec_"+ i +"' class='indivchckbx' /></td><td class='sentdbidcolumn'>"+ sentparseddata[i].id +"</td><td class='useridcolsent'>"+ sentparseddata[i].user_id +"</td><td class='messageidcolsent'>"+ sentparseddata[i].message_id +"</td><td class='datecolsent'>"+ sentparseddata[i].date +"</td><td class='fromcolumnsent'>"+ procsentFrom +"</td><td class='tocolumnsent'>"+ procsentTo +"</td><td class='networkcolumnsent'>"+ sentparseddata[i].network +"</td><td class='pricecolumnsent'>"+ sentparseddata[i].price +"</td><td class='statuscolumnsent'>"+ sentparseddata[i].status +"</td><td class='deliveryrcptcolsent'>"+ sentparseddata[i].deliveryreceipt +"</td><td class='messagecolumnsent'>"+ procmessage +"</td></tr>");
2324
+                    }
2325
+                }
2326
+
2327
+                $('#smstables').append("<div id='totalsentmessages'><span>Total displayed messages: " + sentparseddata.length + "</span></div>");
2328
+
2329
+                $('#smstables').removeClass('icon-loading');
2330
+
2331
+                $('#sentarrow').removeClass('arrowUpCl');
2332
+                $('#sentarrow').addClass('arrowDownCl');
2333
+
2334
+
2335
+                // Show the pop-up window that lists all the messages exchanged between the current 2 phone numbers
2336
+                function showSentMsgPerConv(phNumberFrom, phNumberTo) {
2337
+
2338
+                   let allfrmtomsg = "<div id='listAllMsgsConv'>";
2339
+                   allfrmtomsg += "<div id='draglstMsgmWindow'><img src='/" + ctappdir + "/sms_relentless/img/dots.svg'></div>";
2340
+                   allfrmtomsg += "<a id='closeFrmMsgWindow' title='Close this window'></a>";
2341
+                   allfrmtomsg += "<div class='showByNmbrTitle'>Messages exchanged between <span style='color:#04957b'>"+ phNumberFrom +"</span> and <span style='color:#04957b'>"+ phNumberTo +"</span></div>";
2342
+                   allfrmtomsg += "<div id='frmMsgLstWrap'>";
2343
+                   allfrmtomsg += "<table id='frmMsgLstTbl'>";
2344
+                   allfrmtomsg += "<tr class='groupedrowsbody'><td><div id='grpdbynamelst' class='groupedLstNamespn'></div></td><td><div id='loadMoreMsgs' title='Click to load older messages.'>Load more messages</div><div id='loadMoreMsgsusr' title='Click to load older messages.'>Load more messages</div><div id='msgListRowCell' class='groupedLstMsgspn'></div><div id='refreshMsgsWrap'><div id='refreshMsgsConv' title='Refresh list of messages'></div></div><div id='arrowupWrap'><div id='upArrowSmall' title='Scroll to the top'></div></div></td></tr>";
2345
+                   allfrmtomsg += "</table></div>";
2346
+                   allfrmtomsg += "<div id='sendMsgReply'><table id='sendMsgConv'><tr><td><div id='fromPhoneNmbrConv'>From: <select id='selectFromNbConv'></select></div><div id='toPhoneNmbrConv'>To: <span id='toNmbrConv' style='color:#04957b'>"+ phNumberTo +"</span></div></td></tr>";
2347
+                   allfrmtomsg += "<tr><td><textarea id='sendMsgConvText' placeholder='Enter a message here, then press Send SMS'></textarea></td></tr></table>";
2348
+                   allfrmtomsg += "<div id='sendMsgConvBtn'>Send SMS</div></div>";
2349
+                   allfrmtomsg += "<div style='display:block;width:100%;height:14px;'><img id='expandWindowRpl' src='/" + ctappdir + "/sms_relentless/img/arrowDown.svg' title='Expand to send a reply'></div>";
2350
+                   allfrmtomsg += "<div id='draglstMsgmWindowsc'><img src='/" + ctappdir + "/sms_relentless/img/dots.svg' style='padding:4px;vertical-align:top;'></div>";
2351
+                   allfrmtomsg += "</div>";
2352
+
2353
+                   $("#content").append("<div id='recTblOverlay'></div>");
2354
+                   $("#content").append(allfrmtomsg);
2355
+
2356
+                   let topDist = parseInt((window.innerHeight / 2).toFixed(2) - 340) +"px";
2357
+                   let leftDist = parseInt((window.innerWidth / 2).toFixed(2) - 300) +"px";
2358
+                   $("#listAllMsgsConv").css({ "top" : topDist, "left" : leftDist });
2359
+
2360
+                   $("#closeFrmMsgWindow").click(function() { $("#listAllMsgsConv").remove(); $("#recTblOverlay").remove(); });
2361
+                   $("#recTblOverlay").click(function() { $("#listAllMsgsConv").remove(); $("#recTblOverlay").remove(); });
2362
+
2363
+	           // Expand the window when clicking on the arrow, to be able to send a reply message
2364
+                   $("#expandWindowRpl").unbind("click");
2365
+	           $("#expandWindowRpl").click(function() {
2366
+
2367
+	              if ($(this).attr('src') == '/' + ctappdir + '/sms_relentless/img/arrowDown.svg') {
2368
+                          $("#sendMsgReply").css("display", "block");
2369
+                          $("#listAllMsgsConv").css("height", "618px");
2370
+	                  $(this).attr('src', '/' + ctappdir + '/sms_relentless/img/arrowUp.svg');
2371
+                          $(this).attr('title', 'Collapse');
2372
+
2373
+	              } else {
2374
+
2375
+                          $("#sendMsgReply").css("display", "none");
2376
+                          $("#listAllMsgsConv").css("height", "490px");
2377
+                          $(this).attr('src', '/' + ctappdir + '/sms_relentless/img/arrowDown.svg');
2378
+                          $(this).attr('title', 'Expand to send a reply');
2379
+	              }
2380
+	           });
2381
+
2382
+
2383
+                   // Send a message from the 'conversation' window
2384
+                   $("#sendMsgConvBtn").click(function() {
2385
+
2386
+                      $("#sendMsgConv,#sendMsgConvBtn").addClass('icon-loading');
2387
+                      var msgToSend = $("#sendMsgConvText").val();
2388
+                      var selectedid = $("#selectFromNbConv").val();
2389
+                      var toNumber = $("#toNmbrConv").text();
2390
+                      var receiversNumbers = [toNumber];
2391
+
2392
+		      if (selectedid != '') { 
2393
+
2394
+			  var sendersplit = selectedid.split(":");
2395
+			  var providercap = sendersplit[0];
2396
+			  var provsec = sendersplit[1];
2397
+
2398
+			  if (/[a-zA-Z]/.test(provsec)) {
2399
+			      var alphanumcheck = true;
2400
+			  } else { var alphanumcheck = false; }
2401
+
2402
+			  if (providercap == 'Tx' && alphanumcheck == false) {  
2403
+			      var senderproc = selectedid.replace(/[^0-9]/g, "");
2404
+			      var selectedsender = "+" + senderproc;
2405
+			      var providerUsed = "telnyx";
2406
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmstel");
2407
+			  } else if (providercap == 'Pl' && alphanumcheck == false) {
2408
+			      var selectedsender = selectedid.replace(/[^0-9]/g, "");
2409
+			      var providerUsed = "plivo";
2410
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmsnex");
2411
+			  } else if (providercap == 'Tw' && alphanumcheck == false) {  
2412
+			      var senderproc = selectedid.replace(/[^0-9]/g, "");
2413
+			      var selectedsender = "+" + senderproc;
2414
+			      var providerUsed = "twilio";
2415
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmstwil");
2416
+			  } else if (providercap == 'Fl' && alphanumcheck == false) {  
2417
+			      var senderproc = selectedid.replace(/[^0-9]/g, "");
2418
+			      var selectedsender = "+" + senderproc;
2419
+			      var providerUsed = "flowroute";
2420
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmsflow");
2421
+			  } else if (providercap == 'Tx' && alphanumcheck == true) {
2422
+			      var selectedsender = provsec;
2423
+			      var providerUsed = "telnyx";
2424
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmstel");
2425
+			  } else if (providercap == 'Pl' && alphanumcheck == true) {
2426
+			      var selectedsender = provsec;
2427
+			      var providerUsed = "plivo";
2428
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmsnex");
2429
+			  } else if (providercap == 'Tw' && alphanumcheck == true) {
2430
+			      var selectedsender = provsec;
2431
+			      var providerUsed = "twilio";
2432
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmstwil");
2433
+			  } else if (providercap == 'Fl' && alphanumcheck == true) {
2434
+			      var selectedsender = provsec;
2435
+			      var providerUsed = "flowroute";
2436
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmsflow");
2437
+			  }
2438
+
2439
+                          var uploadedtomms = [];
2440
+
2441
+	                  if (msgToSend != '') {
2442
+
2443
+				  $.ajax({
2444
+				     url: relbaseUrl + '/' + userid,
2445
+				     type: "POST",
2446
+				     data: {
2447
+				           receiversPhoneNbs: receiversNumbers,
2448
+				           fromsender: selectedsender,
2449
+				           waitinterval: 1000,
2450
+				           sentsmstext: msgToSend,
2451
+				           ismms: 0,
2452
+				           mmsfiles: uploadedtomms
2453
+				         },
2454
+				     success: function(displayname) {
2455
+
2456
+                                           var tzdate = new Date();
2457
+                                           var presDatest = new Date(tzdate.getTime() - (tzdate.getTimezoneOffset() * 60000)).toJSON();
2458
+                                           var presDatedb = presDatest.split(".")[0];
2459
+                                           var presDatesc = presDatedb.split("T");
2460
+                                           var presDate = presDatesc[0] +" "+ presDatesc[1];
2461
+                                           var sentMessageStatus = '';
2462
+
2463
+                                           if (displayname) {
2464
+                                               var msgToSendproc = "<span class='msgAuthorNameGrp'>"+ displayname + ":</span>" + msgToSend; 
2465
+                                           } else { var msgToSendproc = msgToSend; }
2466
+
2467
+                                           $("#msgListRowCell").append("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent to current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ selectedsender +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ receiversNumbers[0] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ msgToSendproc +"</div><div style='display:inline-block;margin:6px 6px 0px 4px;font-size:12.5px;color:#353535;'>"+ presDate +"</div><div class='sentMssgStatus'>"+ sentMessageStatus +"</div></div>");
2468
+
2469
+                                           // Scroll down to the bottom of the window
2470
+                                           $("#frmMsgLstWrap").animate({scrollTop:$("#frmMsgLstTbl").prop("scrollHeight")},200);
2471
+
2472
+                                           $("#sendMsgConv,#sendMsgConvBtn").removeClass('icon-loading');
2473
+				     },
2474
+				     error: function() {
2475
+				           showAlert("Error while sending the message. You can check your Nextcloud log to find out more about this issue.");
2476
+				           $("#sendMsgConv,#sendMsgConvBtn").removeClass('icon-loading');
2477
+				     }
2478
+				  });
2479
+			  } else {
2480
+				  showAlert("Please enter a message in the text box!");
2481
+				  $("#sendMsgConv,#sendMsgConvBtn").removeClass('icon-loading');
2482
+			  }
2483
+		      } else {
2484
+			      showAlert("Please choose a Sender ID from the 'From' drop-down list!");
2485
+			      $("#sendMsgConv,#sendMsgConvBtn").removeClass('icon-loading');
2486
+		      }
2487
+
2488
+                   });
2489
+
2490
+
2491
+	           // Make the window draggable
2492
+	           function makeMgrWndDraggable(e) {
2493
+
2494
+			   window.pmdragging = {};
2495
+			   pmdragging.pageX0 = e.pageX;
2496
+			   pmdragging.pageY0 = e.pageY;
2497
+			   pmdragging.elem = $("#listAllMsgsConv");
2498
+			   pmdragging.offset0 = $("#listAllMsgsConv").offset();
2499
+
2500
+			   function handle_dragging(e) {
2501
+			       let left = pmdragging.offset0.left + (e.pageX - pmdragging.pageX0);
2502
+			       let top = pmdragging.offset0.top + (e.pageY - pmdragging.pageY0);
2503
+			       $(pmdragging.elem).offset({top: top, left: left});
2504
+			   }
2505
+
2506
+			   function handle_mouseup(e) {
2507
+			       $('body').off('mousemove', handle_dragging).off('mouseup', handle_mouseup);
2508
+			   }
2509
+
2510
+			   $('body').on('mouseup', handle_mouseup).on('mousemove', handle_dragging);
2511
+	           }
2512
+	           $("#draglstMsgmWindow").mousedown(makeMgrWndDraggable);
2513
+	           $("#draglstMsgmWindowsc").mousedown(makeMgrWndDraggable);
2514
+
2515
+
2516
+                   // Append the available phone numbers to the From drop-down list
2517
+                   var availPhoneNmbrs = [];
2518
+                   $("#currentsmsnmbrs .optselectsmsnb").each(function() {
2519
+                      var crtphnmbr = $(this).attr("value");
2520
+                      if (crtphnmbr != "") { availPhoneNmbrs.push(crtphnmbr); }
2521
+                   });
2522
+
2523
+                   if (availPhoneNmbrs.length > 0) {
2524
+                       var avphopt = "";
2525
+                       for (let d = 0; d < availPhoneNmbrs.length; d++) {
2526
+                            if (availPhoneNmbrs[d].indexOf(phNumberFrom) === -1) {
2527
+                                avphopt += "<option value='"+ availPhoneNmbrs[d] +"'>"+ availPhoneNmbrs[d] +"</option>";
2528
+                            } else {
2529
+                                avphopt += "<option value='"+ availPhoneNmbrs[d] +"' selected>"+ availPhoneNmbrs[d] +"</option>";
2530
+                            }
2531
+                       }
2532
+                       $("#selectFromNbConv").append(avphopt);
2533
+
2534
+                   } else { $("#selectFromNbConv").append("<option value='' selected>No IDs</option>"); }
2535
+
2536
+
2537
+                   // Get the sent/received messages for the current phone numbers, from the database
2538
+                   function getMsgsForNumbersSec(phNumberFrom, phNumberTo) {
2539
+
2540
+			   let getGrpConvUrl = OC.generateUrl("/apps/sms_relentless/user/getgroupedforreply");
2541
+
2542
+			   $('#listAllMsgsConv').addClass('icon-loading');
2543
+			   let totalPhNmbrs = 0;
2544
+
2545
+			   $.ajax({
2546
+				  method: 'POST',
2547
+				  url: getGrpConvUrl + '/' + userid,
2548
+				  contentType: 'application/json',
2549
+		                  data: JSON.stringify({ phoneNmbrFrom: phNumberFrom, phoneNmbrTo: phNumberTo }),
2550
+				  success: function(groupedperconv) {
2551
+
2552
+					     $('#listAllMsgsConv').removeClass('icon-loading');
2553
+
2554
+					     let fromtoNmbrsData = [];
2555
+
2556
+					     for (let i = 0; i < groupedperconv.length; i++) {
2557
+
2558
+						     if (groupedperconv[i].author_displayname) {
2559
+							 var authordnm = groupedperconv[i].author_displayname;
2560
+						     } else { 
2561
+							 var authordnm = '';
2562
+						     }
2563
+
2564
+						     var sentfromnmbrarr = groupedperconv[i].from.split(": ");
2565
+						     if (sentfromnmbrarr[1]) {
2566
+							 var groupednbfrom = sentfromnmbrarr[1];
2567
+						     } else {
2568
+							 var groupednbfrom = sentfromnmbrarr[0];
2569
+						     }
2570
+
2571
+						     var modmessagerec = '';
2572
+						     if (groupedperconv[i].author_displayname) {
2573
+							 modmessagerec = "<span class='msgAuthorNameGrp'>"+ groupedperconv[i].author_displayname + ":</span>" + groupedperconv[i].message;
2574
+						     } else {
2575
+					                 modmessagerec = groupedperconv[i].message;
2576
+		                                     }
2577
+
2578
+						     if (groupedperconv[i].to.indexOf(": ") > -1) {
2579
+						         var groupednmbrtopre = groupedperconv[i].to.split(": ");
2580
+						         var groupednmbrto = groupednmbrtopre[1];
2581
+						     } else { 
2582
+						         var groupednmbrto = groupedperconv[i].to;
2583
+						     }
2584
+
2585
+						     fromtoNmbrsData.push({
2586
+						               'author_displayname': authordnm,
2587
+						               'from': groupednbfrom,
2588
+						               'to': groupednmbrto,
2589
+						               'message': modmessagerec,
2590
+						               'date': groupedperconv[i].date,
2591
+						               'status': groupedperconv[i].deliveryreceipt,
2592
+						               'table': groupedperconv[i].table
2593
+						     });
2594
+					     }
2595
+
2596
+
2597
+					     // Remove the duplicates
2598
+					     let noDupMsgData = [];
2599
+					     $.each(fromtoNmbrsData, function(i, e) {
2600
+						    let matchingData = $.grep(noDupMsgData, function(item) {
2601
+						            return item.from == e.from && item.to == e.to && item.message == e.message && item.table == 'received' && e.table == 'sent';
2602
+						    });
2603
+						    if (matchingData.length === 0) {
2604
+							noDupMsgData.push(e);
2605
+						    }
2606
+					     });
2607
+
2608
+					     let messagesPerNmbr = {};
2609
+					     let msgsNamesPerNmbr = {};
2610
+					     let msgsNmbrsNames = {};
2611
+
2612
+					     let displayNamesarr = [];
2613
+					     let convData = [];
2614
+
2615
+					     for (let n = 0; n < noDupMsgData.length; n++) {
2616
+
2617
+					          if (noDupMsgData[n]['from'] == phNumberTo && noDupMsgData[n]['table'] == 'sent') {
2618
+
2619
+					              convData.push({
2620
+					                             'author_displayname': noDupMsgData[n]['author_displayname'],
2621
+					                             'message': noDupMsgData[n]['message'],
2622
+					                             'from': noDupMsgData[n]['from'],
2623
+					                             'to': noDupMsgData[n]['to'],
2624
+					                             'date': noDupMsgData[n]['date'],
2625
+					                             'direction': 'sent_from',
2626
+					                             'status': noDupMsgData[n]['status'],
2627
+					                             'table': noDupMsgData[n]['table']
2628
+					              });
2629
+
2630
+					          } else if (noDupMsgData[n]['to'] == phNumberTo && noDupMsgData[n]['table'] == 'sent') {
2631
+
2632
+					              convData.push({
2633
+					                             'author_displayname': noDupMsgData[n]['author_displayname'],
2634
+					                             'message': noDupMsgData[n]['message'],
2635
+					                             'from': noDupMsgData[n]['from'],
2636
+					                             'to': noDupMsgData[n]['to'],
2637
+					                             'date': noDupMsgData[n]['date'],
2638
+					                             'direction': 'sent_to',
2639
+					                             'status': noDupMsgData[n]['status'],
2640
+					                             'table': noDupMsgData[n]['table']
2641
+					              });
2642
+
2643
+
2644
+					          } else if (noDupMsgData[n]['from'] == phNumberTo && noDupMsgData[n]['table'] == 'received') {
2645
+
2646
+					              convData.push({
2647
+					                             'author_displayname': noDupMsgData[n]['author_displayname'],
2648
+					                             'message': noDupMsgData[n]['message'],
2649
+					                             'from': noDupMsgData[n]['from'],
2650
+					                             'to': noDupMsgData[n]['to'],
2651
+					                             'date': noDupMsgData[n]['date'],
2652
+					                             'direction': 'received_from',
2653
+					                             'status': noDupMsgData[n]['status'],
2654
+					                             'table': noDupMsgData[n]['table']
2655
+					              });
2656
+
2657
+					          } else if (noDupMsgData[n]['to'] == phNumberTo && noDupMsgData[n]['table'] == 'received') {
2658
+
2659
+					              convData.push({
2660
+					                             'author_displayname': noDupMsgData[n]['author_displayname'],
2661
+					                             'message': noDupMsgData[n]['message'],
2662
+					                             'from': noDupMsgData[n]['from'],
2663
+					                             'to': noDupMsgData[n]['to'],
2664
+					                             'date': noDupMsgData[n]['date'],
2665
+					                             'direction': 'received_on',
2666
+					                             'status': noDupMsgData[n]['status'],
2667
+					                             'table': noDupMsgData[n]['table']
2668
+					              });
2669
+					          }
2670
+					     }
2671
+
2672
+					     // Sort messages by date
2673
+					     convData.sort(function(a, b) {
2674
+						let c = new Date(a.date);
2675
+						let d = new Date(b.date);
2676
+						return c-d;
2677
+					     });
2678
+		                             convData.reverse();
2679
+
2680
+					     // Collect the display names of the users that sent messages from the current number
2681
+					     let selectedNames = [];
2682
+					     let displayNames = '';
2683
+					     for (let v = 0; v < convData.length; v++) {
2684
+					          if (selectedNames.indexOf(convData[v]['author_displayname']) == -1) {
2685
+					              selectedNames.push(convData[v]['author_displayname']);
2686
+					              displayNames += "<div id='diplNm_"+ phNumberTo +"_"+ v +"' class='dispNameList' name='"+ convData[v]['author_displayname'] +"'>"+ convData[v]['author_displayname'] +"</div>";
2687
+					          }
2688
+					     }
2689
+					     displayNames += "<div id='diplNmAllMsg' class='dispNameListAll' title='Show all the messages for this number.'>"+ phNumberTo +"</div>";
2690
+
2691
+					     // Store the display names for the current number, to be able to see them later
2692
+					     let ctPhNumber = phNumberTo;
2693
+					     msgsNamesPerNmbr[ctPhNumber] = displayNames;
2694
+
2695
+					     // Store the messages sent by each user, to be able to see them later when clicking on the user's name
2696
+					     for (let h = 0; h < selectedNames.length; h++) {
2697
+
2698
+					          let rowMessageArrpn = [];
2699
+					          for (let b = 0; b < convData.length; b++) {
2700
+
2701
+					               if (selectedNames[h] == convData[b]['author_displayname']) {
2702
+
2703
+							   if (convData[b]['direction'] == 'sent_from') {
2704
+							       if (convData[b]['status']) {
2705
+							           if (convData[b]['status'].indexOf("delivered") > -1 || convData[b]['status'].indexOf("delivery success") > -1 || convData[b]['status'].indexOf("Retrieved") > -1) {
2706
+							               var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
2707
+							           } else {
2708
+							               var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
2709
+							           }
2710
+							       } else {
2711
+							           var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
2712
+							       }
2713
+							       rowMessageArrpn.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[b]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[b]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[b]['message'] +"</div><div style='display:inline-block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[b]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
2714
+							   } else if (convData[b]['direction'] == 'sent_to') {
2715
+							       if (convData[b]['status']) {
2716
+							           if (convData[b]['status'].indexOf("delivered") > -1 || convData[b]['status'].indexOf("delivery success") > -1 || convData[b]['status'].indexOf("Retrieved") > -1) {
2717
+							               var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
2718
+							           } else {
2719
+							               var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
2720
+							           }
2721
+							       } else {
2722
+							           var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
2723
+							       }
2724
+							       rowMessageArrpn.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent to current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[b]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[b]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[b]['message'] +"</div><div style='display:inline-block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[b]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
2725
+							   } else if (convData[b]['direction'] == 'received_from') {
2726
+							       rowMessageArrpn.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[b]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[b]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[b]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[b]['date'] +"</div></div>");
2727
+							   } else if (convData[b]['direction'] == 'received_on') {
2728
+							       rowMessageArrpn.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received on current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[b]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[b]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[b]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[b]['date'] +"</div></div>");
2729
+					                   }
2730
+					               }
2731
+					          }
2732
+					          let crtNmber = phNumberTo;
2733
+					          let crtName = selectedNames[h];
2734
+					          msgsNmbrsNames[crtNmber] = msgsNmbrsNames[crtNmber] || {};
2735
+		                                  msgsNmbrsNames[crtNmber][crtName] = rowMessageArrpn;
2736
+					     }
2737
+
2738
+		                             // The number of messages to be loaded by default
2739
+		                             let nmbTblDefault = 50;
2740
+
2741
+		                             // If the total number of messages is greater than the default number of messages to display, show the 'Load more messages' button
2742
+		                             if (convData.length > nmbTblDefault) {
2743
+		                                 $("#loadMoreMsgs").css("display", "block");
2744
+		                                 var nmbToBeLoaded = nmbTblDefault;
2745
+		                             } else { var nmbToBeLoaded = convData.length; }
2746
+
2747
+					     let rowMessageArr = [];
2748
+					     for (var m = nmbToBeLoaded - 1; m >= 0; m--) {
2749
+
2750
+					          if (convData[m]['direction'] == 'sent_from') {
2751
+					              if (convData[m]['status']) {
2752
+					                  if (convData[m]['status'].indexOf("delivered") > -1 || convData[m]['status'].indexOf("delivery success") > -1 || convData[m]['status'].indexOf("Retrieved") > -1) {
2753
+					                      let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
2754
+					                  } else {
2755
+					                      let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
2756
+					                  }
2757
+					              } else {
2758
+					                  let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
2759
+					              }
2760
+					              rowMessageArr.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:inline-block;margin:6px 6px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
2761
+
2762
+					          } else if (convData[m]['direction'] == 'sent_to') {
2763
+					              if (convData[m]['status']) {
2764
+					                  if (convData[m]['status'].indexOf("delivered") > -1 || convData[m]['status'].indexOf("delivery success") > -1 || convData[m]['status'].indexOf("Retrieved") > -1) {
2765
+					                      let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
2766
+					                  } else {
2767
+					                      let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
2768
+					                  }
2769
+					              } else {
2770
+					                  let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
2771
+					              }
2772
+					              rowMessageArr.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent to current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:inline-block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
2773
+
2774
+					          } else if (convData[m]['direction'] == 'received_from') {
2775
+
2776
+						      rowMessageArr.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div></div>");
2777
+
2778
+					          } else if (convData[m]['direction'] == 'received_on') {
2779
+
2780
+						      rowMessageArr.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received on current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div></div>");
2781
+					          }
2782
+					     }
2783
+
2784
+					     let convDataPerNmbr = rowMessageArr.join("");
2785
+
2786
+		                             $("#grpdbynamelst").empty();
2787
+		                             $("#grpdbynamelst").append(displayNames);
2788
+		                             $("#msgListRowCell").empty();
2789
+		                             $("#msgListRowCell").append(convDataPerNmbr);
2790
+
2791
+					     // Store the messages for the current number, to be able to see them later, when clicking on the number
2792
+					     let rowMessageArrcpt = [];
2793
+					     for (let m = 0; m < convData.length; m++) {
2794
+
2795
+					          if (convData[m]['direction'] == 'sent_from') {
2796
+					              if (convData[m]['status']) {
2797
+					                  if (convData[m]['status'].indexOf("delivered") > -1 || convData[m]['status'].indexOf("delivery success") > -1 || convData[m]['status'].indexOf("Retrieved") > -1) {
2798
+					                      let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
2799
+					                  } else {
2800
+					                      let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
2801
+					                  }
2802
+					              } else {
2803
+					                  let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
2804
+					              }
2805
+					              rowMessageArrcpt.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:inline-block;margin:6px 6px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
2806
+
2807
+					          } else if (convData[m]['direction'] == 'sent_to') {
2808
+					              if (convData[m]['status']) {
2809
+					                  if (convData[m]['status'].indexOf("delivered") > -1 || convData[m]['status'].indexOf("delivery success") > -1 || convData[m]['status'].indexOf("Retrieved") > -1) {
2810
+					                      let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
2811
+					                  } else {
2812
+					                      let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
2813
+					                  }
2814
+					              } else {
2815
+					                  let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
2816
+					              }
2817
+					              rowMessageArrcpt.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent to current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:inline-block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
2818
+
2819
+					          } else if (convData[m]['direction'] == 'received_from') {
2820
+
2821
+						      rowMessageArrcpt.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div></div>");
2822
+
2823
+					          } else if (convData[m]['direction'] == 'received_on') {
2824
+
2825
+						      rowMessageArrcpt.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received on current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div></div>");
2826
+					          }
2827
+					     }
2828
+
2829
+					     messagesPerNmbr[phNumberTo] = rowMessageArrcpt;
2830
+
2831
+		                             // Scroll down to the bottom of the window
2832
+		                             $("#frmMsgLstWrap").animate({scrollTop:$("#frmMsgLstTbl").prop("scrollHeight")},200);
2833
+
2834
+		                             // Load more messages
2835
+		                             let clickNmb = 0;
2836
+		                             $("#loadMoreMsgs").click(function() {
2837
+
2838
+		                                 clickNmb++;
2839
+
2840
+		                                 var crefnb = (clickNmb + 1) * nmbToBeLoaded;
2841
+
2842
+		                                 if (crefnb > convData.length) {
2843
+		                                     var nmbmsg = convData.length - 1;
2844
+		                                     $("#loadMoreMsgs").css("display", "none");
2845
+		                                 } else { 
2846
+		                                     var nmbmsg = crefnb - 1;
2847
+		                                 }
2848
+
2849
+		                                 var rowMessageArrAdd = [];
2850
+
2851
+		                                 for (let m = nmbmsg; m >= clickNmb * nmbToBeLoaded; m--) {
2852
+
2853
+					              if (convData[m]['direction'] == 'sent_from') {
2854
+					                  if (convData[m]['status']) {
2855
+					                      if (convData[m]['status'].indexOf("delivered") > -1 || convData[m]['status'].indexOf("delivery success") > -1 || convData[m]['status'].indexOf("Retrieved") > -1) {
2856
+					                          let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
2857
+					                      } else {
2858
+					                          let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
2859
+					                      }
2860
+					                  } else {
2861
+					                          let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
2862
+					                  }
2863
+					                  rowMessageArrAdd.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:inline-block;margin:6px 6px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
2864
+
2865
+					              } else if (convData[m]['direction'] == 'sent_to') {
2866
+					                  if (convData[m]['status']) {
2867
+					                      if (convData[m]['status'].indexOf("delivered") > -1 || convData[m]['status'].indexOf("delivery success") > -1 || convData[m]['status'].indexOf("Retrieved") > -1) {
2868
+					                          let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
2869
+					                      } else {
2870
+					                          let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
2871
+					                      }
2872
+					                  } else {
2873
+					                      let sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
2874
+					                  }
2875
+					                  rowMessageArrAdd.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent to current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:inline-block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
2876
+
2877
+					              } else if (convData[m]['direction'] == 'received_from') {
2878
+
2879
+							  rowMessageArrAdd.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div></div>");
2880
+
2881
+					              } else if (convData[m]['direction'] == 'received_on') {
2882
+
2883
+							  rowMessageArrAdd.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received on current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div></div>");
2884
+					              }
2885
+		                                 }
2886
+
2887
+					         let convDataPerNmbrad = rowMessageArrAdd.join("");
2888
+
2889
+		                                 let scrlheight = $("#msgListRowCell").height();
2890
+		                                 $("#msgListRowCell").prepend(convDataPerNmbrad);
2891
+
2892
+		                                 $("#frmMsgLstWrap").scrollTop($("#msgListRowCell").height() - scrlheight);
2893
+		                             });
2894
+
2895
+
2896
+					     // Show the messages sent by each user whose name is clicked
2897
+					     $('[id*="diplNm_"]').click(function() {
2898
+
2899
+					         let crntNmbr = $(this).attr("id").split("_")[1];
2900
+					         let crntDisName = $(this).attr("name");                               
2901
+		                                 $("#loadMoreMsgs").css("display", "none");
2902
+
2903
+		                                 let convDataprn = [];
2904
+		                                 $.each(msgsNmbrsNames[crntNmbr][crntDisName], function(index, item) {
2905
+		                                        convDataprn.push(item);
2906
+		                                 });
2907
+
2908
+		                                 // If the total number of messages is greater than the default number of messages to display, show the 'Load more messages' button
2909
+		                                 if (convDataprn.length > nmbTblDefault) {
2910
+		                                     $("#loadMoreMsgsusr").css("display", "block");
2911
+		                                     let nmbToBeLoaded = nmbTblDefault;
2912
+		                                 } else {
2913
+		                                     $("#loadMoreMsgsusr").css("display", "none");
2914
+		                                     let nmbToBeLoaded = convDataprn.length;
2915
+		                                 }
2916
+
2917
+					         let rowMessageArrprnst = [];
2918
+
2919
+					         for (let n = nmbToBeLoaded - 1; n >= 0; n--) {
2920
+		                                      rowMessageArrprnst.push(convDataprn[n]);
2921
+					         }
2922
+
2923
+					         let convDataPerNmbrprnst = rowMessageArrprnst.join("");
2924
+
2925
+		                                 $("#msgListRowCell").empty();
2926
+		                                 $("#msgListRowCell").append(convDataPerNmbrprnst);
2927
+
2928
+		                                 // Scroll down to the bottom of the window
2929
+		                                 $("#frmMsgLstWrap").animate({scrollTop:$("#frmMsgLstTbl").prop("scrollHeight")},200);
2930
+
2931
+		                                 // Load more messages
2932
+		                                 let clckNb = 0;
2933
+		                                 $("#loadMoreMsgsusr").unbind("click");
2934
+		                                 $("#loadMoreMsgsusr").click(function() {
2935
+
2936
+		                                     clckNb++;
2937
+		                                     var crefnb = (clckNb + 1) * nmbToBeLoaded;
2938
+
2939
+		                                     $("#loadMoreMsgs").css("display", "none");
2940
+
2941
+		                                     if (crefnb > convDataprn.length) {
2942
+		                                         var nmbmsg = convDataprn.length - 1;
2943
+		                                         $("#loadMoreMsgsusr").css("display", "none");
2944
+		                                     } else { 
2945
+		                                         var nmbmsg = crefnb - 1;
2946
+		                                         $("#loadMoreMsgsusr").css("display", "block");
2947
+		                                     }
2948
+
2949
+		                                     var rowMessageArrAddst = [];
2950
+
2951
+		                                     for (var q = nmbmsg; q >= clckNb * nmbToBeLoaded; q--) {
2952
+
2953
+		                                          rowMessageArrAddst.push(convDataprn[q]);
2954
+		                                     }
2955
+
2956
+					             var convDataPerNmbradst = rowMessageArrAddst.join("");
2957
+
2958
+		                                     var scrlheight = $("#msgListRowCell").height();
2959
+		                                     $("#msgListRowCell").prepend(convDataPerNmbradst);
2960
+
2961
+		                                     $("#frmMsgLstWrap").scrollTop($("#msgListRowCell").height() - scrlheight);
2962
+		                                 });
2963
+
2964
+
2965
+					         $(".dispNameList").each(function() { $(this).css("color", "#0a559e"); });
2966
+					         $("#diplNmAllMsg").css("color", "#04957b");
2967
+					         $(this).css("color", "#1b8efe");
2968
+					     });
2969
+
2970
+
2971
+					     // Show again all the messages sent/received to/from the clicked number
2972
+					     $("#diplNmAllMsg").click(function() {
2973
+
2974
+		                                 $("#loadMoreMsgsusr").css("display", "none");
2975
+
2976
+		                                 let convDataprn = [];
2977
+		                                 $.each(messagesPerNmbr[phNumberTo], function(index, item) {
2978
+		                                        convDataprn.push(item);
2979
+		                                 });
2980
+
2981
+		                                 // If the total number of messages is greater than the default number of messages to display, show the 'Load more messages' button
2982
+		                                 if (convDataprn.length > nmbTblDefault) {
2983
+		                                     $("#loadMoreMsgs").css("display", "block");
2984
+		                                     let nmbToBeLoaded = nmbTblDefault;
2985
+		                                 } else {
2986
+		                                     $("#loadMoreMsgs").css("display", "none");
2987
+		                                     let nmbToBeLoaded = convDataprn.length;
2988
+		                                 }
2989
+
2990
+					         let rowMessageArrprnst = [];
2991
+
2992
+					         for (let n = nmbToBeLoaded - 1; n >= 0; n--) {
2993
+		                                      rowMessageArrprnst.push(convDataprn[n]);
2994
+					         }
2995
+
2996
+					         let convDataPerNmbrprnst = rowMessageArrprnst.join("");
2997
+
2998
+		                                 $("#msgListRowCell").empty();
2999
+		                                 $("#msgListRowCell").append(convDataPerNmbrprnst);
3000
+
3001
+		                                 // Scroll down to the bottom of the window
3002
+		                                 $("#frmMsgLstWrap").animate({scrollTop:$("#frmMsgLstTbl").prop("scrollHeight")},200);
3003
+
3004
+
3005
+		                                 // Load more messages
3006
+		                                 let clckNb = 0;
3007
+		                                 $("#loadMoreMsgs").unbind("click");
3008
+		                                 $("#loadMoreMsgs").click(function() {
3009
+
3010
+		                                     clckNb++;
3011
+		                                     var crefnb = (clckNb + 1) * nmbToBeLoaded;
3012
+
3013
+		                                     $("#loadMoreMsgsusr").css("display", "none");
3014
+
3015
+		                                     if (crefnb > convDataprn.length) {
3016
+		                                         var nmbmsg = convDataprn.length - 1;
3017
+		                                         $("#loadMoreMsgs").css("display", "none");
3018
+		                                     } else { 
3019
+		                                         var nmbmsg = crefnb - 1;
3020
+		                                         $("#loadMoreMsgs").css("display", "block");
3021
+		                                     }
3022
+
3023
+		                                     var rowMessageArrAddst = [];
3024
+
3025
+		                                     for (var q = nmbmsg; q >= clckNb * nmbToBeLoaded; q--) {
3026
+
3027
+		                                          rowMessageArrAddst.push(convDataprn[q]);
3028
+		                                     }
3029
+
3030
+					             var convDataPerNmbradst = rowMessageArrAddst.join("");
3031
+
3032
+		                                     var scrlheight = $("#msgListRowCell").height();
3033
+		                                     $("#msgListRowCell").prepend(convDataPerNmbradst);
3034
+
3035
+		                                     $("#frmMsgLstWrap").scrollTop($("#msgListRowCell").height() - scrlheight);
3036
+		                                 });
3037
+
3038
+					         $(".dispNameList").each(function() { $(this).css("color", "#0a559e"); });
3039
+					         $("#diplNmAllMsg").css("color", "#04957b");
3040
+					         $(this).css("color", "#04c6a4");
3041
+					     });
3042
+
3043
+
3044
+					     // Show the scroll-up arrow
3045
+					     $("#frmMsgLstWrap").scroll(function() {
3046
+						if ($(this).scrollTop() > 900) {
3047
+						      $('#upArrowSmall').fadeIn();
3048
+						} else {
3049
+						      $('#upArrowSmall').fadeOut();
3050
+						}
3051
+					     });
3052
+
3053
+					     $("#upArrowSmall").click(function() {
3054
+						$("#frmMsgLstWrap").animate({scrollTop : 0},400);
3055
+					     });
3056
+
3057
+
3058
+					     // Download MMS files when clicking on their URLs
3059
+					     $('[id^="mmsTblUrl-"]').on('click', function(evt) {
3060
+
3061
+					        var clckedUrl = $(this).text();
3062
+					        var flNamearr = clckedUrl.split("/");
3063
+					        var flName = flNamearr.reverse()[0];
3064
+
3065
+					        confirmAlert("Download this file only if you trust the sender and the domain of the URL.");
3066
+
3067
+					        $("#confirmOk").click(function() {
3068
+
3069
+					           $("#alertMsgOverlay").remove();
3070
+					           $("#alertConfMessage").remove();
3071
+
3072
+					           var mmsLink = document.createElement("a");
3073
+					           mmsLink.setAttribute('href', clckedUrl);
3074
+					           mmsLink.setAttribute('download', flName);
3075
+                                                   mmsLink.setAttribute('target', '_blank');
3076
+					           document.body.appendChild(mmsLink);
3077
+					           mmsLink.click();
3078
+					           mmsLink.remove();
3079
+					        });
3080
+
3081
+					        $("#confirmCancel").click(function() { $("#alertMsgOverlay").remove(); $("#alertConfMessage").remove(); });
3082
+					     });
3083
+
3084
+				  },
3085
+				  error: function() {
3086
+					     showAlert("Error while attempting to get message data from the database!");
3087
+					     $('#listAllMsgsConv').removeClass('icon-loading');
3088
+				  }
3089
+			   });
3090
+
3091
+                           // Scroll down to the bottom of the window
3092
+                           $("#frmMsgLstWrap").animate({scrollTop:$("#frmMsgLstTbl").prop("scrollHeight")},200);
3093
+                   }
3094
+
3095
+                   getMsgsForNumbersSec(phNumberFrom, phNumberTo);
3096
+
3097
+                   $("#refreshMsgsConv").click(function() { getMsgsForNumbersSec(phNumberFrom, phNumberTo); setTimeout(function() { $("#diplNmAllMsg").click(); }, 1000); });
3098
+                }
3099
+
3100
+                $('[id^="showMsgConv-"]').click(function() {
3101
+
3102
+                   let ctrwnmbr = $(this).attr("id").replace("showMsgConv-", "");
3103
+                   let phNumberFrom = $("#frmNmbr-"+ ctrwnmbr).text().split(": ")[1];
3104
+                   let phNumberTo = $("#toNmbr-"+ ctrwnmbr).text();
3105
+
3106
+                   showSentMsgPerConv(phNumberFrom, phNumberTo);
3107
+                });
3108
+
3109
+
3110
+                // Show the pop-up window that lists all the messages sent/received to/from a phone number
3111
+                function showMsgPerNmbr(clckPhNumber) {
3112
+
3113
+                   var allfrmtomsg = "<div id='listAllMsgsFromTo'>";
3114
+                   allfrmtomsg += "<div id='draglstMsgmWindow'><img src='/" + ctappdir + "/sms_relentless/img/dots.svg'></div>";
3115
+                   allfrmtomsg += "<a id='closeFrmMsgWindow' title='Close this window'></a>";
3116
+                   allfrmtomsg += "<div class='showByNmbrTitle'>Messages sent/received to/from  <span style='color:#04957b'>"+ clckPhNumber +"</span></div>";
3117
+                   allfrmtomsg += "<div id='frmMsgLstWrap'>";
3118
+                   allfrmtomsg += "<table id='frmMsgLstTbl'>";
3119
+                   allfrmtomsg += "<tr class='groupedrowsbody'><td><div id='grpdbynamelst' class='groupedLstNamespn'></div></td><td><div id='loadMoreMsgs' title='Click to load older messages.'>Load more messages</div><div id='loadMoreMsgsusr' title='Click to load older messages.'>Load more messages</div><div id='msgListRowCell' class='groupedLstMsgspn'></div><div id='refreshMsgsWraptf'><div id='refreshMsgsConvtf' title='Refresh list of messages'></div></div><div id='arrowupWrap'><div id='upArrowSmall' title='Scroll to the top'></div></div></td></tr>";
3120
+                   allfrmtomsg += "</table></div>";
3121
+                   allfrmtomsg += "<div id='sendMsgReply'><table id='sendMsgConv'><tr><td><div id='fromPhoneNmbrConv'>From: <select id='selectFromNbConv'></select></div><div id='toPhoneNmbrConv'>To: <span id='toNmbrConv' style='color:#04957b'>"+ clckPhNumber +"</span></div></td></tr>";
3122
+                   allfrmtomsg += "<tr><td><textarea id='sendMsgConvText' placeholder='Enter a message here, then press Send SMS'></textarea></td></tr></table>";
3123
+                   allfrmtomsg += "<div id='sendMsgConvBtn'>Send SMS</div></div>";
3124
+                   allfrmtomsg += "<div style='display:block;width:100%;height:14px;'><img id='expandWindowRpl' src='/" + ctappdir + "/sms_relentless/img/arrowDown.svg' title='Expand to send a message'></div>";
3125
+                   allfrmtomsg += "<div id='draglstMsgmWindowsc'><img src='/" + ctappdir + "/sms_relentless/img/dots.svg' style='padding:4px;vertical-align:top;'></div>";
3126
+                   allfrmtomsg += "</div>";
3127
+
3128
+                   $("#content").append("<div id='recTblOverlay'></div>");
3129
+                   $("#content").append(allfrmtomsg);
3130
+
3131
+                   var topDist = parseInt((window.innerHeight / 2).toFixed(2) - 340) +"px";
3132
+                   var leftDist = parseInt((window.innerWidth / 2).toFixed(2) - 300) +"px";
3133
+                   $("#listAllMsgsFromTo").css({ "top" : topDist, "left" : leftDist });
3134
+
3135
+                   $("#closeFrmMsgWindow").click(function() { $("#listAllMsgsFromTo").remove(); $("#recTblOverlay").remove(); });
3136
+                   $("#recTblOverlay").click(function() { $("#listAllMsgsFromTo").remove(); $("#recTblOverlay").remove(); });
3137
+
3138
+	           // Expand the window when clicking on the arrow, to be able to send a reply message
3139
+                   $("#expandWindowRpl").unbind("click");
3140
+	           $("#expandWindowRpl").click(function() {
3141
+
3142
+	              if ($(this).attr('src') == '/' + ctappdir + '/sms_relentless/img/arrowDown.svg') {
3143
+                          $("#sendMsgReply").css("display", "block");
3144
+                          $("#listAllMsgsFromTo").css("height", "618px");
3145
+	                  $(this).attr('src', '/' + ctappdir + '/sms_relentless/img/arrowUp.svg');
3146
+                          $(this).attr('title', 'Collapse');
3147
+
3148
+	              } else {
3149
+
3150
+                          $("#sendMsgReply").css("display", "none");
3151
+                          $("#listAllMsgsFromTo").css("height", "490px");
3152
+                          $(this).attr('src', '/' + ctappdir + '/sms_relentless/img/arrowDown.svg');
3153
+                          $(this).attr('title', 'Expand to send a reply');
3154
+	              }
3155
+	           });
3156
+
3157
+
3158
+                   // Send a message from the 'conversation' window
3159
+                   $("#sendMsgConvBtn").click(function() {
3160
+
3161
+                      $("#sendMsgConv,#sendMsgConvBtn").addClass('icon-loading');
3162
+                      var msgToSend = $("#sendMsgConvText").val();
3163
+                      var selectedid = $("#selectFromNbConv").val();
3164
+                      var toNumber = $("#toNmbrConv").text();
3165
+                      var receiversNumbers = [toNumber];
3166
+
3167
+		      if (selectedid != '') {
3168
+
3169
+			  var sendersplit = selectedid.split(":");
3170
+			  var providercap = sendersplit[0];
3171
+			  var provsec = sendersplit[1];
3172
+
3173
+			  if (/[a-zA-Z]/.test(provsec)) {
3174
+			      var alphanumcheck = true;
3175
+			  } else { var alphanumcheck = false; }
3176
+
3177
+			  if (providercap == 'Tx' && alphanumcheck == false) {  
3178
+			      var senderproc = selectedid.replace(/[^0-9]/g, "");
3179
+			      var selectedsender = "+" + senderproc;
3180
+			      var providerUsed = "telnyx";
3181
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmstel");
3182
+			  } else if (providercap == 'Pl' && alphanumcheck == false) {
3183
+			      var selectedsender = selectedid.replace(/[^0-9]/g, "");
3184
+			      var providerUsed = "plivo";
3185
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmsnex");
3186
+			  } else if (providercap == 'Tw' && alphanumcheck == false) {  
3187
+			      var senderproc = selectedid.replace(/[^0-9]/g, "");
3188
+			      var selectedsender = "+" + senderproc;
3189
+			      var providerUsed = "twilio";
3190
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmstwil");
3191
+			  } else if (providercap == 'Fl' && alphanumcheck == false) {  
3192
+			      var senderproc = selectedid.replace(/[^0-9]/g, "");
3193
+			      var selectedsender = "+" + senderproc;
3194
+			      var providerUsed = "flowroute";
3195
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmsflow");
3196
+			  } else if (providercap == 'Tx' && alphanumcheck == true) {
3197
+			      var selectedsender = provsec;
3198
+			      var providerUsed = "telnyx";
3199
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmstel");
3200
+			  } else if (providercap == 'Pl' && alphanumcheck == true) {
3201
+			      var selectedsender = provsec;
3202
+			      var providerUsed = "plivo";
3203
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmsnex");
3204
+			  } else if (providercap == 'Tw' && alphanumcheck == true) {
3205
+			      var selectedsender = provsec;
3206
+			      var providerUsed = "twilio";
3207
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmstwil");
3208
+			  } else if (providercap == 'Fl' && alphanumcheck == true) {
3209
+			      var selectedsender = provsec;
3210
+			      var providerUsed = "flowroute";
3211
+			      var relbaseUrl = OC.generateUrl("/apps/sms_relentless/user/sendsmsflow");
3212
+			  }
3213
+
3214
+                          var uploadedtomms = [];
3215
+
3216
+	                  if (msgToSend != '') {
3217
+
3218
+				  $.ajax({
3219
+				     url: relbaseUrl + '/' + userid,
3220
+				     type: "POST",
3221
+				     data: {
3222
+				           receiversPhoneNbs: receiversNumbers,
3223
+				           fromsender: selectedsender,
3224
+				           waitinterval: 1000,
3225
+				           sentsmstext: msgToSend,
3226
+				           ismms: 0,
3227
+				           mmsfiles: uploadedtomms
3228
+				         },
3229
+				     success: function(displayname) {
3230
+
3231
+                                           var tzdate = new Date();
3232
+                                           var presDatest = new Date(tzdate.getTime() - (tzdate.getTimezoneOffset() * 60000)).toJSON();
3233
+                                           var presDatedb = presDatest.split(".")[0];
3234
+                                           var presDatesc = presDatedb.split("T");
3235
+                                           var presDate = presDatesc[0] +" "+ presDatesc[1];
3236
+                                           var sentMessageStatus = '';
3237
+
3238
+                                           if (displayname) {
3239
+                                               var msgToSendproc = "<span class='msgAuthorNameGrp'>"+ displayname + ":</span>" + msgToSend; 
3240
+                                           } else { var msgToSendproc = msgToSend; }
3241
+
3242
+                                           $("#msgListRowCell").append("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent to current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ selectedsender +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ receiversNumbers[0] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ msgToSendproc +"</div><div style='display:inline-block;margin:6px 6px 0px 4px;font-size:12.5px;color:#353535;'>"+ presDate +"</div><div class='sentMssgStatus'>"+ sentMessageStatus +"</div></div>");
3243
+
3244
+                                           // Scroll down to the bottom of the window
3245
+                                           $("#frmMsgLstWrap").animate({scrollTop:$("#frmMsgLstTbl").prop("scrollHeight")},200);
3246
+
3247
+                                           $("#sendMsgConv,#sendMsgConvBtn").removeClass('icon-loading');
3248
+				     },
3249
+				     error: function() {
3250
+				           showAlert("Error while sending the message. You can check your Nextcloud log to find out more about this issue.");
3251
+				           $("#sendMsgConv,#sendMsgConvBtn").removeClass('icon-loading');
3252
+				     }
3253
+				  });
3254
+			  } else {
3255
+				  showAlert("Please enter a message in the text box!");
3256
+				  $("#sendMsgConv,#sendMsgConvBtn").removeClass('icon-loading');
3257
+			  }
3258
+		      } else {
3259
+			      showAlert("Please choose a Sender ID from the 'From' drop-down list!");
3260
+			      $("#sendMsgConv,#sendMsgConvBtn").removeClass('icon-loading');
3261
+		      }
3262
+
3263
+                   });
3264
+
3265
+
3266
+	           // Make the window draggable
3267
+	           function makeMgrWndDraggable(e) {
3268
+
3269
+			   window.pmdragging = {};
3270
+			   pmdragging.pageX0 = e.pageX;
3271
+			   pmdragging.pageY0 = e.pageY;
3272
+			   pmdragging.elem = $("#listAllMsgsFromTo");
3273
+			   pmdragging.offset0 = $("#listAllMsgsFromTo").offset();
3274
+
3275
+			   function handle_dragging(e) {
3276
+			       var left = pmdragging.offset0.left + (e.pageX - pmdragging.pageX0);
3277
+			       var top = pmdragging.offset0.top + (e.pageY - pmdragging.pageY0);
3278
+			       $(pmdragging.elem).offset({top: top, left: left});
3279
+			   }
3280
+
3281
+			   function handle_mouseup(e) {
3282
+			       $('body').off('mousemove', handle_dragging).off('mouseup', handle_mouseup);
3283
+			   }
3284
+
3285
+			   $('body').on('mouseup', handle_mouseup).on('mousemove', handle_dragging);
3286
+	           }
3287
+	           $("#draglstMsgmWindow").mousedown(makeMgrWndDraggable);
3288
+	           $("#draglstMsgmWindowsc").mousedown(makeMgrWndDraggable);
3289
+
3290
+
3291
+                   // Append the available phone numbers to the From drop-down list
3292
+                   var availPhoneNmbrs = [];
3293
+                   $("#currentsmsnmbrs .optselectsmsnb").each(function() {
3294
+                      var crtphnmbr = $(this).attr("value");
3295
+                      if (crtphnmbr != "") { availPhoneNmbrs.push(crtphnmbr); }
3296
+                   });
3297
+
3298
+                   if (availPhoneNmbrs.length > 0) {
3299
+                       var avphopt = "";
3300
+                       for (let d = 0; d < availPhoneNmbrs.length; d++) {
3301
+                            avphopt += "<option value='"+ availPhoneNmbrs[d] +"'>"+ availPhoneNmbrs[d] +"</option>";
3302
+                       }
3303
+                       $("#selectFromNbConv").append(avphopt);
3304
+
3305
+                   } else { $("#selectFromNbConv").append("<option value='' selected>No IDs</option>"); }
3306
+
3307
+
3308
+                   // Get the sent/received messages for the current phone number, from the database
3309
+                   function getMsgsPerNmbrSec(clckPhNumber) {
3310
+
3311
+			   var getGroupedPnUrl = OC.generateUrl("/apps/sms_relentless/user/getgroupedpernumber");
3312
+
3313
+			   $('#listAllMsgsFromTo').addClass('icon-loading');
3314
+			   var totalPhNmbrs = 0;
3315
+
3316
+			   $.ajax({
3317
+				  method: 'POST',
3318
+				  url: getGroupedPnUrl + '/' + userid,
3319
+				  contentType: 'application/json',
3320
+		                  data: JSON.stringify({ phoneNumber: clckPhNumber }),
3321
+				  success: function(groupedpernb) {
3322
+
3323
+					     $('#listAllMsgsFromTo').removeClass('icon-loading');
3324
+
3325
+					     var fromtoNmbrsData = [];
3326
+
3327
+					     for (var i = 0; i < groupedpernb.length; i++) {
3328
+
3329
+						     if (groupedpernb[i].author_displayname) {
3330
+							 var authordnm = groupedpernb[i].author_displayname;
3331
+						     } else { 
3332
+							 var authordnm = '';
3333
+						     }
3334
+
3335
+						     var sentfromnmbrarr = groupedpernb[i].from.split(": ");
3336
+						     if (sentfromnmbrarr[1]) {
3337
+							 var groupednbfrom = sentfromnmbrarr[1];
3338
+						     } else {
3339
+							 var groupednbfrom = sentfromnmbrarr[0];
3340
+						     }
3341
+
3342
+						     var modmessagesent = '';
3343
+						     if (groupedpernb[i].author_displayname) {
3344
+							 modmessagesent = "<span class='msgAuthorNameGrp'>"+ groupedpernb[i].author_displayname + ":</span>" + groupedpernb[i].message;
3345
+						     } else {
3346
+					                 modmessagesent = groupedpernb[i].message;
3347
+		                                     }
3348
+
3349
+						     if (groupedpernb[i].to.indexOf(": ") > -1) {
3350
+						         var groupednmbrtopre = groupedpernb[i].to.split(": ");
3351
+						         var groupednmbrto = groupednmbrtopre[1];
3352
+						     } else { 
3353
+						         var groupednmbrto = groupedpernb[i].to;
3354
+						     }
3355
+
3356
+						     fromtoNmbrsData.push({
3357
+						               'author_displayname': authordnm,
3358
+						               'from': groupednbfrom,
3359
+						               'to': groupednmbrto,
3360
+						               'message': modmessagesent,
3361
+						               'date': groupedpernb[i].date,
3362
+						               'status': groupedpernb[i].deliveryreceipt,
3363
+						               'table': groupedpernb[i].table
3364
+						     });
3365
+					     }
3366
+
3367
+
3368
+					     // Remove the duplicates
3369
+					     var noDupMsgData = [];
3370
+					     $.each(fromtoNmbrsData, function(i, e) {
3371
+						    var matchingData = $.grep(noDupMsgData, function(item) {
3372
+						            return item.from == e.from && item.to == e.to && item.message == e.message && item.table == 'received' && e.table == 'sent';
3373
+						    });
3374
+						    if (matchingData.length === 0) {
3375
+							noDupMsgData.push(e);
3376
+						    }
3377
+					     });
3378
+
3379
+					     var messagesPerNmbr = {};
3380
+					     var msgsNamesPerNmbr = {};
3381
+					     var msgsNmbrsNames = {};
3382
+
3383
+					     var displayNamesarr = [];
3384
+					     var convData = [];
3385
+
3386
+					     for (var n = 0; n < noDupMsgData.length; n++) {
3387
+
3388
+					          if (noDupMsgData[n]['from'] == clckPhNumber && noDupMsgData[n]['table'] == 'sent') {
3389
+
3390
+					              convData.push({
3391
+					                             'author_displayname': noDupMsgData[n]['author_displayname'],
3392
+					                             'message': noDupMsgData[n]['message'],
3393
+					                             'from': noDupMsgData[n]['from'],
3394
+					                             'to': noDupMsgData[n]['to'],
3395
+					                             'date': noDupMsgData[n]['date'],
3396
+					                             'direction': 'sent_from',
3397
+					                             'status': (noDupMsgData[n]['status'] == null)? "" : noDupMsgData[n]['status'],
3398
+					                             'table': noDupMsgData[n]['table']
3399
+					              });
3400
+
3401
+					          } else if (noDupMsgData[n]['to'] == clckPhNumber && noDupMsgData[n]['table'] == 'sent') {
3402
+
3403
+					              convData.push({
3404
+					                             'author_displayname': noDupMsgData[n]['author_displayname'],
3405
+					                             'message': noDupMsgData[n]['message'],
3406
+					                             'from': noDupMsgData[n]['from'],
3407
+					                             'to': noDupMsgData[n]['to'],
3408
+					                             'date': noDupMsgData[n]['date'],
3409
+					                             'direction': 'sent_to',
3410
+					                             'status': (noDupMsgData[n]['status'] == null)? "" : noDupMsgData[n]['status'],
3411
+					                             'table': noDupMsgData[n]['table']
3412
+					              });
3413
+
3414
+
3415
+					          } else if (noDupMsgData[n]['from'] == clckPhNumber && noDupMsgData[n]['table'] == 'received') {
3416
+
3417
+					              convData.push({
3418
+					                             'author_displayname': noDupMsgData[n]['author_displayname'],
3419
+					                             'message': noDupMsgData[n]['message'],
3420
+					                             'from': noDupMsgData[n]['from'],
3421
+					                             'to': noDupMsgData[n]['to'],
3422
+					                             'date': noDupMsgData[n]['date'],
3423
+					                             'direction': 'received_from',
3424
+					                             'status': (noDupMsgData[n]['status'] == null)? "" : noDupMsgData[n]['status'],
3425
+					                             'table': noDupMsgData[n]['table']
3426
+					              });
3427
+
3428
+					          } else if (noDupMsgData[n]['to'] == clckPhNumber && noDupMsgData[n]['table'] == 'received') {
3429
+
3430
+					              convData.push({
3431
+					                             'author_displayname': noDupMsgData[n]['author_displayname'],
3432
+					                             'message': noDupMsgData[n]['message'],
3433
+					                             'from': noDupMsgData[n]['from'],
3434
+					                             'to': noDupMsgData[n]['to'],
3435
+					                             'date': noDupMsgData[n]['date'],
3436
+					                             'direction': 'received_on',
3437
+					                             'status': (noDupMsgData[n]['status'] == null)? "" : noDupMsgData[n]['status'],
3438
+					                             'table': noDupMsgData[n]['table']
3439
+					              });
3440
+					          }
3441
+					     }
3442
+
3443
+					     // Sort messages by date
3444
+					     convData.sort(function(a, b) {
3445
+						var c = new Date(a.date);
3446
+						var d = new Date(b.date);
3447
+						return c-d;
3448
+					     });
3449
+		                             convData.reverse();
3450
+
3451
+					     // Collect the display names of the users that sent messages from the current number
3452
+					     var selectedNames = [];
3453
+					     var displayNames = '';
3454
+					     for (var v = 0; v < convData.length; v++) {
3455
+					          if (selectedNames.indexOf(convData[v]['author_displayname']) == -1) { 
3456
+					              selectedNames.push(convData[v]['author_displayname']);
3457
+					              displayNames += "<div id='diplNm_"+ clckPhNumber +"_"+ v +"' class='dispNameList' name='"+ convData[v]['author_displayname'] +"'>"+ convData[v]['author_displayname'] +"</div>";
3458
+					          }
3459
+					     }
3460
+					     displayNames += "<div id='diplNmAllMsg' class='dispNameListAll' title='Show all the messages for this number.'>"+ clckPhNumber +"</div>";
3461
+
3462
+					     // Store the display names for the current number, to be able to see them later
3463
+					     var ctPhNumber = clckPhNumber;
3464
+					     msgsNamesPerNmbr[ctPhNumber] = displayNames;
3465
+
3466
+					     // Store the messages sent by each user, to be able to see them later when clicking on the user's name
3467
+					     for (var h = 0; h < selectedNames.length; h++) {
3468
+
3469
+					          var rowMessageArrpn = [];
3470
+					          for (var b = 0; b < convData.length; b++) {
3471
+
3472
+					               if (selectedNames[h] == convData[b]['author_displayname']) {
3473
+
3474
+							   if (convData[b]['direction'] == 'sent_from') {
3475
+							       if (convData[b]['status']) {
3476
+							           if (convData[b]['status'].indexOf("delivered") > -1 || convData[b]['status'].indexOf("delivery success") > -1 || convData[b]['status'].indexOf("Retrieved") > -1) {
3477
+							               var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
3478
+							           } else {
3479
+							               var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
3480
+							           }
3481
+							       } else {
3482
+							           var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
3483
+							       }
3484
+							       rowMessageArrpn.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[b]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[b]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[b]['message'] +"</div><div style='display:inline-block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[b]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
3485
+							   } else if (convData[b]['direction'] == 'sent_to') {
3486
+							       if (convData[b]['status']) {
3487
+							           if (convData[b]['status'].indexOf("delivered") > -1 || convData[b]['status'].indexOf("delivery success") > -1 || convData[b]['status'].indexOf("Retrieved") > -1) {
3488
+							               var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
3489
+							           } else {
3490
+							               var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
3491
+							           }
3492
+							       } else {
3493
+							           var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
3494
+							       }
3495
+							       rowMessageArrpn.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent to current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[b]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[b]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[b]['message'] +"</div><div style='display:inline-block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[b]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
3496
+							   } else if (convData[b]['direction'] == 'received_from') {
3497
+							       rowMessageArrpn.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[b]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[b]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[b]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[b]['date'] +"</div></div>");
3498
+							   } else if (convData[b]['direction'] == 'received_on') {
3499
+							       rowMessageArrpn.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received on current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[b]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[b]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[b]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[b]['date'] +"</div></div>");
3500
+					                   }
3501
+					               }
3502
+					          }
3503
+					          var crtNmber = clckPhNumber;
3504
+					          var crtName = selectedNames[h];
3505
+					          msgsNmbrsNames[crtNmber] = msgsNmbrsNames[crtNmber] || {};
3506
+		                                  msgsNmbrsNames[crtNmber][crtName] = rowMessageArrpn;
3507
+					     }
3508
+
3509
+		                             // The number of messages to be loaded by default
3510
+		                             var nmbTblDefault = 50;
3511
+
3512
+		                             // If the total number of messages is greater than the default number of messages to display, show the 'Load more messages' button
3513
+		                             if (convData.length > nmbTblDefault) {
3514
+		                                 $("#loadMoreMsgs").css("display", "block");
3515
+		                                 var nmbToBeLoaded = nmbTblDefault;
3516
+		                             } else { var nmbToBeLoaded = convData.length; }
3517
+
3518
+					     var rowMessageArr = [];
3519
+					     for (var m = nmbToBeLoaded - 1; m >= 0; m--) {
3520
+
3521
+					          if (convData[m]['direction'] == 'sent_from') {
3522
+					              if (convData[m]['status']) {
3523
+					                  if (convData[m]['status'].indexOf("delivered") > -1 || convData[m]['status'].indexOf("delivery success") > -1 || convData[m]['status'].indexOf("Retrieved") > -1) {
3524
+					                      var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
3525
+					                  } else {
3526
+					                      var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
3527
+					                  }
3528
+					              } else {
3529
+					                  var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
3530
+					              }    
3531
+					              rowMessageArr.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:inline-block;margin:6px 6px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
3532
+
3533
+					          } else if (convData[m]['direction'] == 'sent_to') {
3534
+					              if (convData[m]['status']) {
3535
+					                  if (convData[m]['status'].indexOf("delivered") > -1 || convData[m]['status'].indexOf("delivery success") > -1 || convData[m]['status'].indexOf("Retrieved") > -1) {
3536
+					                      var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
3537
+					                  } else {
3538
+					                      var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
3539
+					                  }
3540
+					              } else {
3541
+					                  var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
3542
+					              }
3543
+					              rowMessageArr.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent to current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:inline-block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
3544
+
3545
+					          } else if (convData[m]['direction'] == 'received_from') {
3546
+
3547
+						      rowMessageArr.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div></div>");
3548
+
3549
+					          } else if (convData[m]['direction'] == 'received_on') {
3550
+
3551
+						      rowMessageArr.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received on current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div></div>");
3552
+					          }
3553
+					     }
3554
+
3555
+					     var convDataPerNmbr = rowMessageArr.join("");
3556
+		                             $("#grpdbynamelst").empty();
3557
+		                             $("#grpdbynamelst").append(displayNames);
3558
+		                             $("#msgListRowCell").empty();
3559
+		                             $("#msgListRowCell").append(convDataPerNmbr);
3560
+
3561
+					     // Store the messages for the current number, to be able to see them later, when clicking on the number
3562
+					     var rowMessageArrcpt = [];
3563
+					     for (var m = 0; m < convData.length; m++) {
3564
+
3565
+					          if (convData[m]['direction'] == 'sent_from') {
3566
+					              if (convData[m]['status']) {
3567
+					                  if (convData[m]['status'].indexOf("delivered") > -1 || convData[m]['status'].indexOf("delivery success") > -1 || convData[m]['status'].indexOf("Retrieved") > -1) {
3568
+					                      var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
3569
+					                  } else {
3570
+					                      var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
3571
+					                  }
3572
+					              } else {
3573
+					                  var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
3574
+					              }
3575
+					              rowMessageArrcpt.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:inline-block;margin:6px 6px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
3576
+
3577
+					          } else if (convData[m]['direction'] == 'sent_to') {
3578
+					              if (convData[m]['status']) {
3579
+					                  if (convData[m]['status'].indexOf("delivered") > -1 || convData[m]['status'].indexOf("delivery success") > -1 || convData[m]['status'].indexOf("Retrieved") > -1) {
3580
+					                      var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
3581
+					                  } else {
3582
+					                      var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
3583
+					                  }
3584
+					              } else {
3585
+					                  var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
3586
+					              }
3587
+					              rowMessageArrcpt.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent to current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:inline-block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
3588
+
3589
+					          } else if (convData[m]['direction'] == 'received_from') {
3590
+
3591
+						      rowMessageArrcpt.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div></div>");
3592
+
3593
+					          } else if (convData[m]['direction'] == 'received_on') {
3594
+
3595
+						      rowMessageArrcpt.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received on current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div></div>");
3596
+					          }
3597
+					     }
3598
+
3599
+					     messagesPerNmbr[clckPhNumber] = rowMessageArrcpt;
3600
+
3601
+		                             // Scroll down to the bottom of the window
3602
+		                             $("#frmMsgLstWrap").animate({scrollTop:$("#frmMsgLstTbl").prop("scrollHeight")},200);
3603
+
3604
+		                             // Load more messages
3605
+		                             var clickNmb = 0;
3606
+		                             $("#loadMoreMsgs").click(function() {
3607
+
3608
+		                                 clickNmb++;
3609
+
3610
+		                                 var crefnb = (clickNmb + 1) * nmbToBeLoaded;
3611
+
3612
+		                                 if (crefnb > convData.length) {
3613
+		                                     var nmbmsg = convData.length - 1;
3614
+		                                     $("#loadMoreMsgs").css("display", "none");
3615
+		                                 } else { 
3616
+		                                     var nmbmsg = crefnb - 1;
3617
+		                                 }
3618
+
3619
+		                                 var rowMessageArrAdd = [];
3620
+
3621
+		                                 for (var m = nmbmsg; m >= clickNmb * nmbToBeLoaded; m--) {
3622
+
3623
+					              if (convData[m]['direction'] == 'sent_from') {
3624
+					                  if (convData[m]['status']) {
3625
+					                      if (convData[m]['status'].indexOf("delivered") > -1 || convData[m]['status'].indexOf("delivery success") > -1 || convData[m]['status'].indexOf("Retrieved") > -1) {
3626
+					                          var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
3627
+					                      } else {
3628
+					                          var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
3629
+					                      }
3630
+					                  } else {
3631
+					                      var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
3632
+					                  }
3633
+					                  rowMessageArrAdd.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:inline-block;margin:6px 6px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
3634
+
3635
+					              } else if (convData[m]['direction'] == 'sent_to') {
3636
+					                  if (convData[m]['status']) {
3637
+					                      if (convData[m]['status'].indexOf("delivered") > -1 || convData[m]['status'].indexOf("delivery success") > -1 || convData[m]['status'].indexOf("Retrieved") > -1) {
3638
+					                          var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
3639
+					                      } else {
3640
+					                          var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
3641
+					                      }
3642
+					                  } else {
3643
+					                      var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
3644
+					                  }
3645
+					                  rowMessageArrAdd.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent to current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:inline-block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
3646
+
3647
+					              } else if (convData[m]['direction'] == 'received_from') {
3648
+
3649
+							  rowMessageArrAdd.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div></div>");
3650
+
3651
+					              } else if (convData[m]['direction'] == 'received_on') {
3652
+
3653
+							  rowMessageArrAdd.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received on current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div></div>");
3654
+					              }
3655
+		                                 }
3656
+
3657
+					         var convDataPerNmbrad = rowMessageArrAdd.join("");
3658
+
3659
+		                                 var scrlheight = $("#msgListRowCell").height();
3660
+		                                 $("#msgListRowCell").prepend(convDataPerNmbrad);
3661
+
3662
+		                                 $("#frmMsgLstWrap").scrollTop($("#msgListRowCell").height() - scrlheight);
3663
+		                             });
3664
+
3665
+
3666
+					     // Show the messages sent by each user whose name is clicked
3667
+					     $('[id*="diplNm_"]').click(function() {
3668
+
3669
+					         var crntNmbr = $(this).attr("id").split("_")[1];
3670
+					         var crntDisName = $(this).attr("name");                               
3671
+		                                 $("#loadMoreMsgs").css("display", "none");
3672
+
3673
+		                                 var convDataprn = [];
3674
+		                                 $.each(msgsNmbrsNames[crntNmbr][crntDisName], function(index, item) {
3675
+		                                        convDataprn.push(item);
3676
+		                                 });
3677
+
3678
+		                                 // If the total number of messages is greater than the default number of messages to display, show the 'Load more messages' button
3679
+		                                 if (convDataprn.length > nmbTblDefault) {
3680
+		                                     $("#loadMoreMsgsusr").css("display", "block");
3681
+		                                     var nmbToBeLoaded = nmbTblDefault;
3682
+		                                 } else {
3683
+		                                     $("#loadMoreMsgsusr").css("display", "none");
3684
+		                                     var nmbToBeLoaded = convDataprn.length;
3685
+		                                 }
3686
+
3687
+					         var rowMessageArrprnst = [];
3688
+
3689
+					         for (var n = nmbToBeLoaded - 1; n >= 0; n--) {
3690
+		                                      rowMessageArrprnst.push(convDataprn[n]);
3691
+					         }
3692
+
3693
+					         var convDataPerNmbrprnst = rowMessageArrprnst.join("");
3694
+
3695
+		                                 $("#msgListRowCell").empty();
3696
+		                                 $("#msgListRowCell").append(convDataPerNmbrprnst);
3697
+
3698
+		                                 // Scroll down to the bottom of the window
3699
+		                                 $("#frmMsgLstWrap").animate({scrollTop:$("#frmMsgLstTbl").prop("scrollHeight")},200);
3700
+
3701
+		                                 // Load more messages
3702
+		                                 var clckNb = 0;
3703
+		                                 $("#loadMoreMsgsusr").unbind("click");
3704
+		                                 $("#loadMoreMsgsusr").click(function() {
3705
+
3706
+		                                     clckNb++;
3707
+		                                     var crefnb = (clckNb + 1) * nmbToBeLoaded;
3708
+
3709
+		                                     $("#loadMoreMsgs").css("display", "none");
3710
+
3711
+		                                     if (crefnb > convDataprn.length) {
3712
+		                                         var nmbmsg = convDataprn.length - 1;
3713
+		                                         $("#loadMoreMsgsusr").css("display", "none");
3714
+		                                     } else { 
3715
+		                                         var nmbmsg = crefnb - 1;
3716
+		                                         $("#loadMoreMsgsusr").css("display", "block");
3717
+		                                     }
3718
+
3719
+		                                     var rowMessageArrAddst = [];
3720
+
3721
+		                                     for (var q = nmbmsg; q >= clckNb * nmbToBeLoaded; q--) {
3722
+
3723
+		                                          rowMessageArrAddst.push(convDataprn[q]);
3724
+		                                     }
3725
+
3726
+					             var convDataPerNmbradst = rowMessageArrAddst.join("");
3727
+
3728
+		                                     var scrlheight = $("#msgListRowCell").height();
3729
+		                                     $("#msgListRowCell").prepend(convDataPerNmbradst);
3730
+
3731
+		                                     $("#frmMsgLstWrap").scrollTop($("#msgListRowCell").height() - scrlheight);
3732
+		                                 });
3733
+
3734
+
3735
+					         $(".dispNameList").each(function() { $(this).css("color", "#0a559e"); });
3736
+					         $("#diplNmAllMsg").css("color", "#04957b");
3737
+					         $(this).css("color", "#1b8efe");
3738
+					     });
3739
+
3740
+
3741
+					     // Show again all the messages sent/received to/from the clicked number
3742
+					     $("#diplNmAllMsg").click(function() {
3743
+
3744
+		                                 $("#loadMoreMsgsusr").css("display", "none");
3745
+
3746
+		                                 var convDataprn = [];
3747
+		                                 $.each(messagesPerNmbr[clckPhNumber], function(index, item) {
3748
+		                                        convDataprn.push(item);
3749
+		                                 });
3750
+
3751
+		                                 // If the total number of messages is greater than the default number of messages to display, show the 'Load more messages' button
3752
+		                                 if (convDataprn.length > nmbTblDefault) {
3753
+		                                     $("#loadMoreMsgs").css("display", "block");
3754
+		                                     var nmbToBeLoaded = nmbTblDefault;
3755
+		                                 } else {
3756
+		                                     $("#loadMoreMsgs").css("display", "none");
3757
+		                                     var nmbToBeLoaded = convDataprn.length;
3758
+		                                 }
3759
+
3760
+					         var rowMessageArrprnst = [];
3761
+
3762
+					         for (var n = nmbToBeLoaded - 1; n >= 0; n--) {
3763
+		                                      rowMessageArrprnst.push(convDataprn[n]);
3764
+					         }
3765
+
3766
+					         var convDataPerNmbrprnst = rowMessageArrprnst.join("");
3767
+
3768
+		                                 $("#msgListRowCell").empty();
3769
+		                                 $("#msgListRowCell").append(convDataPerNmbrprnst);
3770
+
3771
+		                                 // Scroll down to the bottom of the window
3772
+		                                 $("#frmMsgLstWrap").animate({scrollTop:$("#frmMsgLstTbl").prop("scrollHeight")},200);
3773
+
3774
+
3775
+		                                 // Load more messages
3776
+		                                 var clckNb = 0;
3777
+		                                 $("#loadMoreMsgs").unbind("click");
3778
+		                                 $("#loadMoreMsgs").click(function() {
3779
+
3780
+		                                     clckNb++;
3781
+		                                     var crefnb = (clckNb + 1) * nmbToBeLoaded;
3782
+
3783
+		                                     $("#loadMoreMsgsusr").css("display", "none");
3784
+
3785
+		                                     if (crefnb > convDataprn.length) {
3786
+		                                         var nmbmsg = convDataprn.length - 1;
3787
+		                                         $("#loadMoreMsgs").css("display", "none");
3788
+		                                     } else {
3789
+		                                         var nmbmsg = crefnb - 1;
3790
+		                                         $("#loadMoreMsgs").css("display", "block");
3791
+		                                     }
3792
+
3793
+		                                     var rowMessageArrAddst = [];
3794
+
3795
+		                                     for (var q = nmbmsg; q >= clckNb * nmbToBeLoaded; q--) {
3796
+
3797
+		                                          rowMessageArrAddst.push(convDataprn[q]);
3798
+		                                     }
3799
+
3800
+					             var convDataPerNmbradst = rowMessageArrAddst.join("");
3801
+
3802
+		                                     var scrlheight = $("#msgListRowCell").height();
3803
+		                                     $("#msgListRowCell").prepend(convDataPerNmbradst);
3804
+
3805
+		                                     $("#frmMsgLstWrap").scrollTop($("#msgListRowCell").height() - scrlheight);
3806
+		                                 });
3807
+
3808
+
3809
+					         $(".dispNameList").each(function() { $(this).css("color", "#0a559e"); });
3810
+					         $("#diplNmAllMsg").css("color", "#04957b");
3811
+					         $(this).css("color", "#04c6a4");
3812
+					     });
3813
+
3814
+
3815
+					     // Show the scroll-up arrow
3816
+					     $("#frmMsgLstWrap").scroll(function() {
3817
+						if ($(this).scrollTop() > 900) {
3818
+						      $('#upArrowSmall').fadeIn();
3819
+						} else {
3820
+						      $('#upArrowSmall').fadeOut();
3821
+						}
3822
+					     });
3823
+
3824
+					     $("#upArrowSmall").click(function() {
3825
+						$("#frmMsgLstWrap").animate({scrollTop : 0},400);
3826
+					     });
3827
+
3828
+
3829
+					     // Download MMS files when clicking on their URLs
3830
+					     $('[id^="mmsTblUrl-"]').on('click', function(evt) {
3831
+
3832
+					        var clckedUrl = $(this).text();
3833
+					        var flNamearr = clckedUrl.split("/");
3834
+					        var flName = flNamearr.reverse()[0];
3835
+
3836
+					        confirmAlert("Download this file only if you trust the sender and the domain of the URL.");
3837
+
3838
+					        $("#confirmOk").click(function() {
3839
+
3840
+					           $("#alertMsgOverlay").remove();
3841
+					           $("#alertConfMessage").remove();
3842
+
3843
+					           var mmsLink = document.createElement("a");
3844
+					           mmsLink.setAttribute('href', clckedUrl);
3845
+					           mmsLink.setAttribute('download', flName);
3846
+                                                   mmsLink.setAttribute('target', '_blank');
3847
+					           document.body.appendChild(mmsLink);
3848
+					           mmsLink.click();
3849
+					           mmsLink.remove();
3850
+					        });
3851
+
3852
+					        $("#confirmCancel").click(function() { $("#alertMsgOverlay").remove(); $("#alertConfMessage").remove(); });
3853
+					     });
3854
+
3855
+				  },
3856
+				  error: function() {
3857
+					     showAlert("Error while attempting to get message data from the database!");
3858
+					     $('#listAllMsgsFromTo').removeClass('icon-loading');
3859
+				  }
3860
+			   });
3861
+
3862
+                           // Scroll down to the bottom of the window
3863
+                           $("#frmMsgLstWrap").animate({scrollTop:$("#frmMsgLstTbl").prop("scrollHeight")},200);
3864
+                   }
3865
+
3866
+                   getMsgsPerNmbrSec(clckPhNumber);
3867
+
3868
+                   $("#refreshMsgsConvtf").click(function() { getMsgsPerNmbrSec(clckPhNumber); setTimeout(function() { $("#diplNmAllMsg").click(); }, 1000); });
3869
+                }
3870
+
3871
+
3872
+                $('[id^="showMsgFrom-"]').click(function() {
3873
+
3874
+                   var ctrwnb = $(this).attr("id").replace("showMsgFrom-", "");
3875
+                   if ($("#frmNmbr-"+ ctrwnb).text().indexOf(":") > -1) {
3876
+                       var clckPhNumber = $("#frmNmbr-"+ ctrwnb).text().split(": ")[1];
3877
+                   } else { var clckPhNumber = $("#frmNmbr-"+ ctrwnb).text(); }
3878
+
3879
+                   showMsgPerNmbr(clckPhNumber);
3880
+                })
3881
+
3882
+                $('[id^="showMsgTo-"]').click(function() {
3883
+                   var ctrwnbTo = $(this).attr("id").replace("showMsgTo-", "");
3884
+                   var clckPhNbTo = $("#toNmbr-"+ ctrwnbTo).text();
3885
+
3886
+                   showMsgPerNmbr(clckPhNbTo);
3887
+                })
3888
+
3889
+
3890
+                // Add pagination
3891
+                var rowsShown = messagesperpage;
3892
+                var rowsTotal = $("#sentSmsTable tr").length;
3893
+                var numPages = (rowsTotal - 2) / rowsShown;
3894
+
3895
+                for (i = 0; i < numPages; i++) {
3896
+                     var pageNum = i + 1;
3897
+                     $('#paginationsent').append('<a href="#" rel="' + i + '" class="pagenumbers">' + pageNum + '</a> ');
3898
+                }
3899
+
3900
+                $('#paginationsent').children(":first").addClass('active');
3901
+
3902
+                $('#paginationsent a:first').addClass('active');
3903
+
3904
+                // Show table page when clicking on page number
3905
+                $('.pages a').bind('click', function () {
3906
+
3907
+                      $('#paginationsent').children().removeClass('active');
3908
+
3909
+                      $(this).addClass('active');
3910
+
3911
+                      var currentsentPgNo = $(this).text();
3912
+
3913
+                      $('#paginationsent a').each(function() {
3914
+                         if ($(this).text() == currentsentPgNo) {
3915
+                             $(this).addClass('active');
3916
+                         }
3917
+                      });
3918
+
3919
+                      // Sort table rows
3920
+		      var rows = $('#sentSmsTable tr').get();
3921
+
3922
+		      rows.sort(function(a, b) {
3923
+
3924
+		           var A = parseInt($('td.sentdbidcolumn', a).text());
3925
+		           var B = parseInt($('td.sentdbidcolumn', b).text());
3926
+
3927
+		           if (A < B) {
3928
+		               return -1;
3929
+		           }
3930
+
3931
+		           if (A > B) {
3932
+		               return 1;
3933
+		           }
3934
+
3935
+		           return 0;
3936
+		      });
3937
+
3938
+		      $.each(rows, function(index, row) {
3939
+		         $('#sentSmsTable').append(row);
3940
+		      });
3941
+
3942
+                      var currPage = $(this).attr('rel');
3943
+                      var startItem = currPage * rowsShown;
3944
+                      var endItem = startItem + rowsShown;
3945
+
3946
+                      $('.sentrowsbody').hide().slice(startItem, endItem).css('display', 'table-row');
3947
+
3948
+                      $('#totalsentmessages').remove();
3949
+                      $('#smstables').append("<div id='totalsentmessages'>Total displayed messages: " + sentparseddata.length + "</div>");
3950
+                });
3951
+
3952
+                $('#paginationsent').children(":last").trigger('click');
3953
+
3954
+                // Select all records
3955
+                $('#selectAllChckbx').change(function() {
3956
+                   if ($(this).is(':checked')) {
3957
+                       $(".indivchckbx").prop("checked", true);
3958
+                   } else {
3959
+                       $(".indivchckbx").prop("checked", false);
3960
+                   }
3961
+                });
3962
+
3963
+                function reorderSentRows() {
3964
+                    var currenttext = $(".filterbuttonsent").closest('[class="filterbuttonsent"]').find('[class="indivfiltersent"]').text();
3965
+                    if (currenttext == '') {
3966
+                        $('tr').sort(function (a, b) {
3967
+                           return parseInt($('td.sentdbidcolumn', b).text()) < parseInt($('td.sentdbidcolumn', a).text());
3968
+                        }).appendTo("#sentSmsTable");
3969
+                    }
3970
+                }
3971
+
3972
+                // Filter rows
3973
+                $("#databaseidfilter").on("click", function(event) {
3974
+
3975
+                       var databaseId = $("#dbidtextsent").val();
3976
+                       var msgrowsNo = 0;
3977
+
3978
+                       $(".sentrowsbody").each(function() {
3979
+
3980
+                          var checkEmpty = 0;
3981
+                          $(".indivfiltersent").not("#dbidtextsent").each(function() {
3982
+                              if ($(this).val() != '') {
3983
+                                  checkEmpty = 1;
3984
+                              }
3985
+                          });
3986
+
3987
+                          if (checkEmpty == 0) {
3988
+                              $(this).show();
3989
+                          }
3990
+
3991
+                          if (databaseId != '') {
3992
+                             if ($(this).find('[class="sentdbidcolumn"]').text() == databaseId) {
3993
+                                 $("#sentSmsTable").append(this);
3994
+                                 if ($(this).is(":visible")) { msgrowsNo++; }
3995
+                             } else {
3996
+                                 $(this).hide();
3997
+                             }
3998
+                          } else {
3999
+                                 $(this).show();
4000
+                                 msgrowsNo++;
4001
+                          }
4002
+                       });
4003
+
4004
+                       reorderSentRows();
4005
+                       $('#totalsentmessages').remove();
4006
+                       $('#smstables').append("<div id='totalsentmessages'>Total filtered messages: " + msgrowsNo + "</div>");
4007
+                });
4008
+
4009
+                $("#useridfilter").on("click", function(event) {
4010
+
4011
+                       var useridtxt = $("#useridtext").val().toLowerCase();
4012
+                       var msgrowsNo = 0;
4013
+
4014
+                       $(".sentrowsbody").each(function() {
4015
+
4016
+                          var checkEmpty1 = 0;
4017
+                          $(".indivfiltersent").not("#useridtext").each(function() {
4018
+                              if ($(this).val() != '') {
4019
+                                  checkEmpty1 = 1;
4020
+                              }
4021
+                          });
4022
+
4023
+                          if (checkEmpty1 == 0) {
4024
+                              $(this).show();
4025
+                          }
4026
+
4027
+                          if (useridtxt != '') {
4028
+                              var founduserid = $(this).find('[class="useridcolsent"]').text().toLowerCase();
4029
+                              if (founduserid.indexOf(useridtxt) != -1) {
4030
+                                  $("#sentSmsTable").append(this);
4031
+                                  if ($(this).is(":visible")) { msgrowsNo++; }
4032
+                             } else {
4033
+                                  $(this).hide();
4034
+                             }
4035
+                          } else {
4036
+                                  $(this).show();
4037
+                                  msgrowsNo++;
4038
+                          }
4039
+                       });
4040
+
4041
+                       reorderSentRows();
4042
+                       $('#totalsentmessages').remove();
4043
+                       $('#smstables').append("<div id='totalsentmessages'>Total filtered messages: " + msgrowsNo + "</div>");
4044
+                });
4045
+
4046
+                $("#messageidfilter").on("click", function(event) {
4047
+
4048
+                       var messageidtxt = $("#messageidtext").val().toLowerCase();
4049
+                       var msgrowsNo = 0;
4050
+
4051
+                       $(".sentrowsbody").each(function() {
4052
+
4053
+                          var checkEmpty2 = 0;
4054
+                          $(".indivfiltersent").not("#messageidtext").each(function() {
4055
+                              if ($(this).val() != '') {
4056
+                                  checkEmpty2 = 1;
4057
+                              }
4058
+                          });
4059
+
4060
+                          if (checkEmpty2 == 0) {
4061
+                              $(this).show();
4062
+                          }
4063
+
4064
+                          if (messageidtxt != '') {
4065
+                              var foundtdmssgid = $(this).find('[class="messageidcolsent"]').text().toLowerCase();
4066
+                              if (foundtdmssgid.indexOf(messageidtxt) != -1) {
4067
+                                  $("#sentSmsTable").append(this);
4068
+                                  if ($(this).is(":visible")) { msgrowsNo++; }
4069
+                              } else {
4070
+                                  $(this).hide();
4071
+                              }
4072
+                          } else {
4073
+                                  $(this).show();
4074
+                                  msgrowsNo++;
4075
+                          }
4076
+                       });
4077
+
4078
+                       reorderSentRows();
4079
+                       $('#totalsentmessages').remove();
4080
+                       $('#smstables').append("<div id='totalsentmessages'>Total filtered messages: " + msgrowsNo + "</div>");
4081
+                });
4082
+
4083
+                $("#datefilter").on("click", function(event) {
4084
+
4085
+                       var datetxtvr = $("#datetext").val().toLowerCase();
4086
+                       var msgrowsNo = 0;
4087
+
4088
+                       $(".sentrowsbody").each(function() {
4089
+
4090
+                          var checkEmpty3 = 0;
4091
+                          $(".indivfiltersent").not("#datetext").each(function() {
4092
+                              if ($(this).val() != '') {
4093
+                                  checkEmpty3 = 1;
4094
+                              }
4095
+                          });
4096
+
4097
+                          if (checkEmpty3 == 0) {
4098
+                              $(this).show();
4099
+                          }
4100
+
4101
+                          if (datetxtvr != '') {
4102
+                             var founddate = $(this).find('[class="datecolsent"]').text().toLowerCase();
4103
+                             if (founddate.indexOf(datetxtvr) != -1) {
4104
+                                 $("#sentSmsTable").append(this);
4105
+                                 if ($(this).is(":visible")) { msgrowsNo++; }
4106
+                             } else {
4107
+                                 $(this).hide();
4108
+                             }
4109
+                          } else {
4110
+                                 $(this).show();
4111
+                                 msgrowsNo++;
4112
+                          }
4113
+                       });
4114
+
4115
+                       reorderSentRows();
4116
+                       $('#totalsentmessages').remove();
4117
+                       $('#smstables').append("<div id='totalsentmessages'>Total filtered messages: " + msgrowsNo + "</div>");
4118
+                });
4119
+
4120
+                $("#fromfilter").on("click", function(event) {
4121
+
4122
+                       var fromtxtvr = $("#fromtext").val().toLowerCase();
4123
+                       var msgrowsNo = 0;
4124
+
4125
+                       $(".sentrowsbody").each(function() {
4126
+
4127
+                          var checkEmpty4 = 0;
4128
+                          $(".indivfiltersent").not("#fromtext").each(function() {
4129
+                              if ($(this).val() != '') {
4130
+                                  checkEmpty4 = 1;
4131
+                              }
4132
+                          });
4133
+
4134
+                          if (checkEmpty4 == 0) {
4135
+                              $(this).show();
4136
+                          }
4137
+
4138
+                          if (fromtxtvr != '') {
4139
+                             var foundfrom = $(this).find('[class="fromcolumnsent"]').text().toLowerCase();
4140
+                             if (foundfrom.indexOf(fromtxtvr) != -1) {
4141
+                                 $("#sentSmsTable").append(this);
4142
+                                 if ($(this).is(":visible")) { msgrowsNo++; }
4143
+                             } else {
4144
+                                 $(this).hide();
4145
+                             }
4146
+                          } else {
4147
+                                 $(this).show();
4148
+                                 msgrowsNo++;
4149
+                          }
4150
+                       });
4151
+
4152
+                       reorderSentRows();
4153
+                       $('#totalsentmessages').remove();
4154
+                       $('#smstables').append("<div id='totalsentmessages'>Total filtered messages: " + msgrowsNo + "</div>");
4155
+                });
4156
+
4157
+                $("#tofilter").on("click", function(event) {
4158
+
4159
+                      var totxtvr = $("#totext").val().toLowerCase();
4160
+                      var msgrowsNo = 0;
4161
+
4162
+                      $(".sentrowsbody").each(function() {
4163
+
4164
+                          var checkEmpty5 = 0;
4165
+                          $(".indivfiltersent").not("#totext").each(function() {
4166
+                              if ($(this).val() != '') {
4167
+                                  checkEmpty5 = 1;
4168
+                              }
4169
+                          });
4170
+
4171
+                          if (checkEmpty5 == 0) {
4172
+                              $(this).show();
4173
+                          }
4174
+
4175
+                          if (totxtvr != '') {
4176
+                             var foundto = $(this).find('[class="tocolumnsent"]').text().toLowerCase();
4177
+                             if (foundto.indexOf(totxtvr) != -1) {
4178
+                                 $("#sentSmsTable").append(this);
4179
+                                 if ($(this).is(":visible")) { msgrowsNo++; }
4180
+                             } else {
4181
+                                 $(this).hide();
4182
+                             }
4183
+                          } else {
4184
+                                 $(this).show();
4185
+                                 msgrowsNo++;
4186
+                          }
4187
+                      });
4188
+
4189
+                      reorderSentRows();
4190
+                      $('#totalsentmessages').remove();
4191
+                      $('#smstables').append("<div id='totalsentmessages'>Total filtered messages: " + msgrowsNo + "</div>");
4192
+                });
4193
+
4194
+                $("#networkfilter").on("click", function(event) {
4195
+
4196
+                      var networktxtvr = $("#networktext").val().toLowerCase();
4197
+                      var msgrowsNo = 0;
4198
+
4199
+                      $(".sentrowsbody").each(function() {
4200
+
4201
+                          var checkEmpty6 = 0;
4202
+                          $(".indivfiltersent").not("#networktext").each(function() {
4203
+                              if ($(this).val() != '') {
4204
+                                  checkEmpty6 = 1;
4205
+                              }
4206
+                          });
4207
+
4208
+                          if (checkEmpty6 == 0) {
4209
+                              $(this).show();
4210
+                          }
4211
+
4212
+                          if (networktxtvr != '') {
4213
+                              var foundnetwork = $(this).find('[class="networkcolumnsent"]').text().toLowerCase();
4214
+                              if (foundnetwork.indexOf(networktxtvr) != -1) {
4215
+                                  $("#sentSmsTable").append(this);
4216
+                                  if ($(this).is(":visible")) { msgrowsNo++; }
4217
+                              } else {
4218
+                                  $(this).hide();
4219
+                              }
4220
+                          } else {
4221
+                                  $(this).show();
4222
+                                  msgrowsNo++;
4223
+                          }
4224
+                      });
4225
+
4226
+                      reorderSentRows();
4227
+                      $('#totalsentmessages').remove();
4228
+                      $('#smstables').append("<div id='totalsentmessages'>Total filtered messages: " + msgrowsNo + "</div>");
4229
+                });
4230
+
4231
+                $("#pricefilter").on("click", function(event) {
4232
+
4233
+                      var pricetxtvr = $("#pricetext").val().toLowerCase();
4234
+                      var msgrowsNo = 0;
4235
+
4236
+                      $(".sentrowsbody").each(function() {
4237
+
4238
+                          var checkEmpty7 = 0;
4239
+                          $(".indivfiltersent").not("#pricetext").each(function() {
4240
+                              if ($(this).val() != '') {
4241
+                                  checkEmpty7 = 1;
4242
+                              }
4243
+                          });
4244
+
4245
+                          if (checkEmpty7 == 0) {
4246
+                              $(this).show();
4247
+                          }
4248
+
4249
+                          if (pricetxtvr != '') {
4250
+                              var foundprice = $(this).find('[class="pricecolumnsent"]').text().toLowerCase();
4251
+                              if (foundprice.indexOf(pricetxtvr) != -1) {
4252
+                                  $("#sentSmsTable").append(this);
4253
+                                  if ($(this).is(":visible")) { msgrowsNo++; }
4254
+                              } else {
4255
+                                  $(this).hide();
4256
+                              }
4257
+                          } else {
4258
+                                  $(this).show();
4259
+                                  msgrowsNo++;
4260
+                          }
4261
+                      });
4262
+
4263
+                      reorderSentRows();
4264
+                      $('#totalsentmessages').remove();
4265
+                      $('#smstables').append("<div id='totalsentmessages'>Total filtered messages: " + msgrowsNo + "</div>");
4266
+                });
4267
+
4268
+                $("#statusfilter").on("click", function(event) {
4269
+
4270
+                      var statustxtvr = $("#statustext").val().toLowerCase();
4271
+                      var msgrowsNo = 0;
4272
+
4273
+                      $(".sentrowsbody").each(function() {
4274
+
4275
+                          var checkEmpty8 = 0;
4276
+                          $(".indivfiltersent").not("#statustext").each(function() {
4277
+                              if ($(this).val() != '') {
4278
+                                  checkEmpty8 = 1;
4279
+                              }
4280
+                          });
4281
+
4282
+                          if (checkEmpty8 == 0) {
4283
+                              $(this).show();
4284
+                          }
4285
+
4286
+                          if (statustxtvr != '') {
4287
+                              var foundstatus = $(this).find('[class="statuscolumnsent"]').text().toLowerCase();
4288
+                              if (foundstatus.indexOf(statustxtvr) != -1) {
4289
+                                  $("#sentSmsTable").append(this);
4290
+                                  if ($(this).is(":visible")) { msgrowsNo++; }
4291
+                              } else {
4292
+                                  $(this).hide();
4293
+                              }
4294
+                          } else {
4295
+                                  $(this).show();
4296
+                                  msgrowsNo++;
4297
+                          }
4298
+                      });
4299
+
4300
+                      reorderSentRows();
4301
+                      $('#totalsentmessages').remove();
4302
+                      $('#smstables').append("<div id='totalsentmessages'>Total filtered messages: " + msgrowsNo + "</div>");
4303
+                });
4304
+
4305
+                $("#deliveryrecfilter").on("click", function(event) {
4306
+
4307
+                      var deliverytxtvr = $("#deliveryrcpttext").val().toLowerCase();
4308
+                      var msgrowsNo = 0;
4309
+
4310
+                      $(".sentrowsbody").each(function() {
4311
+
4312
+                          var checkEmpty9 = 0;
4313
+                          $(".indivfiltersent").not("#deliveryrcpttext").each(function() {
4314
+                              if ($(this).val() != '') {
4315
+                                  checkEmpty9 = 1;
4316
+                              }
4317
+                          });
4318
+
4319
+                          if (checkEmpty9 == 0) {
4320
+                              $(this).show();
4321
+                          }
4322
+
4323
+                          if (deliverytxtvr != '') {
4324
+                              var founddeliveryrcpt = $(this).find('[class="deliveryrcptcolsent"]').text().toLowerCase();
4325
+                              if (founddeliveryrcpt.indexOf(deliverytxtvr) != -1) {
4326
+                                  $("#sentSmsTable").append(this);
4327
+                                  if ($(this).is(":visible")) { msgrowsNo++; }
4328
+                              } else {
4329
+                                  $(this).hide();
4330
+                              }
4331
+                          } else {
4332
+                                  $(this).show();
4333
+                                  msgrowsNo++;
4334
+                          }
4335
+                      });
4336
+
4337
+                      reorderSentRows();
4338
+                      $('#totalsentmessages').remove();
4339
+                      $('#smstables').append("<div id='totalsentmessages'>Total filtered messages: " + msgrowsNo + "</div>");
4340
+                });
4341
+
4342
+                $("#messagefilter").on("click", function(event) {
4343
+
4344
+                      var messagetxtvr = $("#messagetext").val().toLowerCase();
4345
+                      var msgrowsNo = 0;
4346
+
4347
+                      $(".sentrowsbody").each(function() {
4348
+
4349
+                          var checkEmpty10 = 0;
4350
+                          $(".indivfiltersent").not("#messagetext").each(function() {
4351
+                              if ($(this).val() != '') {
4352
+                                  checkEmpty10 = 1;
4353
+                              }
4354
+                          });
4355
+
4356
+                          if (checkEmpty10 == 0) {
4357
+                              $(this).show();
4358
+                          }
4359
+
4360
+                          if (messagetxtvr != '') {
4361
+                              var foundmessage = $(this).find('[class="messagecolumnsent"]').text().toLowerCase();
4362
+                              if (foundmessage.indexOf(messagetxtvr) != -1) {
4363
+                                  $("#sentSmsTable").append(this);
4364
+                                  if ($(this).is(":visible")) { msgrowsNo++; }
4365
+                              } else {
4366
+                                  $(this).hide();
4367
+                              }
4368
+                          } else {
4369
+                                  $(this).show();
4370
+                                  msgrowsNo++;
4371
+                          }
4372
+                      });
4373
+
4374
+                      reorderSentRows();
4375
+                      $('#totalsentmessages').remove();
4376
+                      $('#smstables').append("<div id='totalsentmessages'>Total filtered messages: " + msgrowsNo + "</div>");
4377
+                });
4378
+
4379
+                // Clear all filters
4380
+                $("#clearsentfilters").on("click", function(event) {
4381
+                       $(".sentrowsbody").each(function() {
4382
+                          $(this).show();
4383
+                       });
4384
+                       $(".indivfiltersent").val("");
4385
+                       $('#totalsentmessages').remove();
4386
+                       $('#smstables').append("<div id='totalsentmessages'>Total displayed messages: " + sentparseddata.length + "</div>");
4387
+                });
4388
+
4389
+                // Delete selected rows from the database
4390
+                $("#deletesentrows").on("click", function() {
4391
+
4392
+                   var checkcheckbx = jQuery("#sentSmsTable input[type=checkbox]:checked").length;
4393
+                   if (checkcheckbx == 0) {
4394
+                       showAlert("Please select the row(s) to permanently delete from the database !");
4395
+                   } else {
4396
+                          var sentcheckboxIds = [];
4397
+                          $(".sentrowsbody").each(function() {
4398
+                             var sentrowcheckbx = $(this).find('input[type="checkbox"]');
4399
+                             if (sentrowcheckbx.is(":checked")) {
4400
+                                 var dbrowid = $(this).find('[class="sentdbidcolumn"]').text();
4401
+                                 sentcheckboxIds.push(dbrowid);
4402
+                             }
4403
+                          });
4404
+
4405
+		          confirmAlert("Please note that the row(s) you selected will be permanently deleted from the database, without being saved before removal. This action cannot be undone ! If you really want to permanently delete the selected row(s) press 'OK'.");
4406
+
4407
+		          $("#confirmCancel").click(function() { $("#alertMsgOverlay").remove(); $("#alertConfMessage").remove(); });
4408
+
4409
+		          $("#confirmOk").click(function() {
4410
+
4411
+		              $("#alertMsgOverlay").remove();
4412
+		              $("#alertConfMessage").remove();
4413
+
4414
+                              var deletesentRowsUrl = OC.generateUrl("/apps/sms_relentless/user/removesentrows");
4415
+                              $('#smstables').addClass('icon-loading');
4416
+
4417
+                              $.ajax({
4418
+                                   url: deletesentRowsUrl + '/' + userid,
4419
+                                   method: "POST",
4420
+                                   dataType:'text',
4421
+                                   data: {sentmessagedbIDs: sentcheckboxIds},
4422
+                                   success: function() {
4423
+                                            showAlert("The row(s) have been deleted successfully !");
4424
+                                            $('#smstables').removeClass('icon-loading');
4425
+                                            $('#sentsmstableshow').click();
4426
+                                   },
4427
+                                   error: function() {
4428
+                                            showAlert("There was an error while deleting the selected row(s) !");
4429
+                                            $('#smstables').removeClass('icon-loading');
4430
+                                   }
4431
+                              });
4432
+                          });
4433
+                    }
4434
+                });
4435
+
4436
+                // Show/Hide filter row
4437
+	        $('#sentarrow').on('click', function() {
4438
+	           if ($('#sentfiltersrow').is(':visible')) {
4439
+		       $('#sentfiltersrow').hide();
4440
+                       $('#sentheaderrow').css('top', '0px');
4441
+                       $(this).removeClass('arrowUpCl');
4442
+                       $(this).addClass('arrowDownCl');
4443
+		   } else {
4444
+		       $('#sentfiltersrow').show();
4445
+                       $('#sentheaderrow').css('top', '158px');
4446
+                       $(this).removeClass('arrowDownCl');
4447
+                       $(this).addClass('arrowUpCl');
4448
+                   }
4449
+                });
4450
+
4451
+                $("#app-content").animate({scrollTop:$("#sentSmsTable").prop("scrollHeight")},200);
4452
+
4453
+
4454
+                // Download MMS files when clicking on their URLs
4455
+                $('[id^="mmsTblUrl-"]').on('click', function(evt) {
4456
+
4457
+                   var clckedUrl = $(this).text();
4458
+                   var flNamearr = clckedUrl.split("/");
4459
+                   var flName = flNamearr.reverse()[0];
4460
+
4461
+                   confirmAlert("Download this file only if you trust the sender and the domain of the URL.");
4462
+
4463
+		   $("#confirmOk").click(function() {
4464
+
4465
+                      $("#alertMsgOverlay").remove();
4466
+		      $("#alertConfMessage").remove();
4467
+
4468
+		      var mmsLink = document.createElement("a");
4469
+		      mmsLink.setAttribute('href', clckedUrl);
4470
+		      mmsLink.setAttribute('download', flName);
4471
+                      mmsLink.setAttribute('target', '_blank');
4472
+		      document.body.appendChild(mmsLink);
4473
+		      mmsLink.click();
4474
+		      mmsLink.remove();
4475
+                   });
4476
+
4477
+		   $("#confirmCancel").click(function() { $("#alertMsgOverlay").remove(); $("#alertConfMessage").remove(); });
4478
+                });
4479
+
4480
+          },
4481
+          error: function(sentdatafromdb) {
4482
+                showAlert("Error! You can check the Nextcloud log to find more details about this issue.");
4483
+                $('#smstables').removeClass('icon-loading');
4484
+          }
4485
+     });
4486
+
4487
+     // Look for the 'new received message' indicator in the database, to know if the received messages list needs to be refreshed
4488
+     intervalNmfr = setInterval(function() { checkIfNewMessage(); }, newMsgInterval);
4489
+
4490
+     // Show the auto-refresh button
4491
+     $("#stopAutoRefreshSent").css("display", "inline-block");
4492
+
4493
+  });
4494
+
4495
+
4496
+  // List grouped messages
4497
+  $("#groupedtableshow").on("click", function(event) {
4498
+
4499
+     $('#smstables').empty();
4500
+     clearInterval(intervalNmfr);
4501
+
4502
+     var getGroupedUrl = OC.generateUrl("/apps/sms_relentless/user/getgroupedtable");
4503
+
4504
+     $('#smstables').addClass('icon-loading');
4505
+     var totalPhNmbrs = 0;
4506
+
4507
+     $.ajax({
4508
+          method: 'GET',
4509
+          url: getGroupedUrl + '/' + userid,
4510
+          contentType: 'application/json',
4511
+          success: function(groupedparsed) {
4512
+
4513
+		        $('#smstables').append("<div id='toptablegrp'><div class='topbuttonandpage'><span id='recarrow' title='Show/Hide filters'></span></div><div id='paginationgrp' class='grppages'>Pages </div></div>");
4514
+		        $('#smstables').append("<table id='groupedSmsTable'></table>");
4515
+
4516
+                        $('#groupedSmsTable').append("<tr id='grpfiltersrow'><td colspan='2'><div id='filterByNumber'></div></td><td><button id='cleargrpfilter' title='Clear the filter'></button></td></tr>");
4517
+                        $('#groupedSmsTable').append("<tr class='groupedmsgrows' id='grpheaderrow'><th>Phone Number</th><th>Senders / Receivers</th><th>Messages</th></tr>");
4518
+
4519
+                        $('#grpfiltersrow').hide();
4520
+
4521
+                        var fromtoNmbrsData = [];
4522
+                        var fromtoNumberArr = [];
4523
+
4524
+		        for (var i = 0; i < groupedparsed.length; i++) {
4525
+
4526
+			     if (groupedparsed[i].author_displayname) {
4527
+			         var authordnm = groupedparsed[i].author_displayname;
4528
+			     } else { 
4529
+			         var authordnm = '';
4530
+			     }
4531
+
4532
+			     var sentfromnmbrarr = groupedparsed[i].from.split(": ");
4533
+                             if (sentfromnmbrarr[1]) {
4534
+			         var groupednbfrom = sentfromnmbrarr[1];
4535
+                             } else {
4536
+			         var groupednbfrom = sentfromnmbrarr[0];
4537
+                             }
4538
+
4539
+                             var modmessage = '';
4540
+                             if (groupedparsed[i].author_displayname) {
4541
+			         modmessage = "<span class='msgAuthorNameGrp'>"+ groupedparsed[i].author_displayname + ":</span>" + groupedparsed[i].message;
4542
+                             } else {
4543
+			         modmessage = groupedparsed[i].message;
4544
+                             }
4545
+
4546
+                             if (groupedparsed[i].to.indexOf(": ") > -1) {
4547
+                                 var groupednmbrtopre = groupedparsed[i].to.split(": ");
4548
+                                 var groupednmbrto = groupednmbrtopre[1];
4549
+                             } else { 
4550
+                                 var groupednmbrto = groupedparsed[i].to;
4551
+                             }
4552
+
4553
+                             fromtoNmbrsData.push({
4554
+                                       'author_displayname': authordnm,
4555
+                                       'from': groupednbfrom,
4556
+                                       'to': groupednmbrto,
4557
+                                       'message': modmessage,
4558
+                                       'date': groupedparsed[i].date,
4559
+                                       'status': groupedparsed[i].deliveryreceipt,
4560
+                                       'table': groupedparsed[i].table
4561
+                             });
4562
+
4563
+                             if (fromtoNumberArr.indexOf(groupednbfrom) == -1) { fromtoNumberArr.push(groupednbfrom); }
4564
+                             if (fromtoNumberArr.indexOf(groupednmbrto) == -1) { fromtoNumberArr.push(groupednmbrto); }
4565
+		        }
4566
+
4567
+                        totalPhNmbrs = fromtoNumberArr.length;
4568
+
4569
+                        // Remove the duplicates
4570
+			var noDupMsgData = [];
4571
+			$.each(fromtoNmbrsData, function(i, e) {
4572
+			    var matchingData = $.grep(noDupMsgData, function(item) {
4573
+                                return item.from == e.from && item.to == e.to && item.message == e.message && item.table == 'received' && e.table == 'sent'
4574
+			    });
4575
+			    if (matchingData.length === 0) {
4576
+				noDupMsgData.push(e);
4577
+			    }
4578
+			});
4579
+
4580
+                        var messagesPerNmbr = {};
4581
+                        var msgsNamesPerNmbr = {};
4582
+                        var msgsNmbrsNames = {};
4583
+
4584
+                        for (var k = 0; k < fromtoNumberArr.length; k++) {
4585
+
4586
+                             var displayNamesarr = [];
4587
+                             var convData = [];
4588
+
4589
+                             for (var n = 0; n < noDupMsgData.length; n++) {
4590
+
4591
+                                  if (noDupMsgData[n]['from'] == fromtoNumberArr[k] && noDupMsgData[n]['table'] == 'sent') {
4592
+
4593
+                                      convData.push({
4594
+                                                     'author_displayname': noDupMsgData[n]['author_displayname'],
4595
+                                                     'message': noDupMsgData[n]['message'],
4596
+                                                     'from': noDupMsgData[n]['from'],
4597
+                                                     'to': noDupMsgData[n]['to'],
4598
+                                                     'date': noDupMsgData[n]['date'],
4599
+                                                     'direction': 'sent_from',
4600
+                                                     'status': (noDupMsgData[n]['status'] == null)? "" : noDupMsgData[n]['status'],
4601
+                                                     'table': noDupMsgData[n]['table']
4602
+                                      });
4603
+
4604
+                                  } else if (noDupMsgData[n]['to'] == fromtoNumberArr[k] && noDupMsgData[n]['table'] == 'sent') {
4605
+
4606
+                                      convData.push({
4607
+                                                     'author_displayname': noDupMsgData[n]['author_displayname'],
4608
+                                                     'message': noDupMsgData[n]['message'],
4609
+                                                     'from': noDupMsgData[n]['from'],
4610
+                                                     'to': noDupMsgData[n]['to'],
4611
+                                                     'date': noDupMsgData[n]['date'],
4612
+                                                     'direction': 'sent_to',
4613
+                                                     'status': (noDupMsgData[n]['status'] == null)? "" : noDupMsgData[n]['status'],
4614
+                                                     'table': noDupMsgData[n]['table']
4615
+                                      });
4616
+
4617
+
4618
+                                  } else if (noDupMsgData[n]['from'] == fromtoNumberArr[k] && noDupMsgData[n]['table'] == 'received') {
4619
+
4620
+                                      convData.push({
4621
+                                                     'author_displayname': noDupMsgData[n]['author_displayname'],
4622
+                                                     'message': noDupMsgData[n]['message'],
4623
+                                                     'from': noDupMsgData[n]['from'],
4624
+                                                     'to': noDupMsgData[n]['to'],
4625
+                                                     'date': noDupMsgData[n]['date'],
4626
+                                                     'direction': 'received_from',
4627
+                                                     'status': (noDupMsgData[n]['status'] == null)? "" : noDupMsgData[n]['status'],
4628
+                                                     'table': noDupMsgData[n]['table']
4629
+                                      });
4630
+
4631
+                                  } else if (noDupMsgData[n]['to'] == fromtoNumberArr[k] && noDupMsgData[n]['table'] == 'received') {
4632
+
4633
+                                      convData.push({
4634
+                                                     'author_displayname': noDupMsgData[n]['author_displayname'],
4635
+                                                     'message': noDupMsgData[n]['message'],
4636
+                                                     'from': noDupMsgData[n]['from'],
4637
+                                                     'to': noDupMsgData[n]['to'],
4638
+                                                     'date': noDupMsgData[n]['date'],
4639
+                                                     'direction': 'received_on',
4640
+                                                     'status': (noDupMsgData[n]['status'] == null)? "" : noDupMsgData[n]['status'],
4641
+                                                     'table': noDupMsgData[n]['table']
4642
+                                      });
4643
+                                  }
4644
+                             }
4645
+
4646
+                             // Sort messages by date
4647
+		             convData.sort(function(a, b) {
4648
+			        var c = new Date(a.date);
4649
+			        var d = new Date(b.date);
4650
+			        return c-d;
4651
+		             });
4652
+
4653
+                             // Collect the display names of the users that sent messages from the current number
4654
+                             var selectedNames = [];
4655
+                             var displayNames = '';
4656
+                             for (var v = 0; v < convData.length; v++) {
4657
+                                  if (selectedNames.indexOf(convData[v]['author_displayname']) == -1) { 
4658
+                                      selectedNames.push(convData[v]['author_displayname']);
4659
+                                      displayNames += "<div id='diplNm_"+ fromtoNumberArr[k] +"_"+ v +"' class='dispNameList' name='"+ convData[v]['author_displayname'] +"'>"+ convData[v]['author_displayname'] +"</div>";
4660
+                                  }
4661
+                             }
4662
+
4663
+                             // Store the display names for the current number, to be able to see them later when selecting the number from the drop-down list
4664
+                             var ctPhNumber = fromtoNumberArr[k];
4665
+                             msgsNamesPerNmbr[ctPhNumber] = displayNames;
4666
+
4667
+                             // Store the messages sent by each user, to be able to see them later when clicking on the user's name
4668
+                             for (var h = 0; h < selectedNames.length; h++) {
4669
+
4670
+                                  var rowMessageArrpn = [];
4671
+                                  for (var b = 0; b < convData.length; b++) {
4672
+
4673
+                                       if (selectedNames[h] == convData[b]['author_displayname']) {
4674
+
4675
+		                           if (convData[b]['direction'] == 'sent_from') {
4676
+		                               if (convData[b]['status']) {
4677
+		                                   if (convData[b]['status'].indexOf("delivered") > -1 || convData[b]['status'].indexOf("delivery success") > -1 || convData[b]['status'].indexOf("Retrieved") > -1) {
4678
+		                                       var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
4679
+		                                   } else {
4680
+		                                       var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
4681
+		                                   }
4682
+		                               } else {
4683
+		                                   var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
4684
+		                               }
4685
+		                               rowMessageArrpn.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[b]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[b]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[b]['message'] +"</div><div style='display:inline-block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[b]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
4686
+		                           } else if (convData[b]['direction'] == 'sent_to') {
4687
+		                               if (convData[b]['status']) {
4688
+		                                   if (convData[b]['status'].indexOf("delivered") > -1 || convData[b]['status'].indexOf("delivery success") > -1 || convData[b]['status'].indexOf("Retrieved") > -1) {
4689
+		                                       var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
4690
+		                                   } else {
4691
+		                                       var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
4692
+		                                   }
4693
+		                               } else {
4694
+		                                   var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
4695
+		                               }
4696
+		                               rowMessageArrpn.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent to current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[b]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[b]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[b]['message'] +"</div><div style='display:inline-block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[b]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
4697
+		                           } else if (convData[b]['direction'] == 'received_from') {
4698
+		                               rowMessageArrpn.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[b]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[b]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[b]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[b]['date'] +"</div></div>");
4699
+		                           } else if (convData[b]['direction'] == 'received_on') {
4700
+		                               rowMessageArrpn.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received on current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[b]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[b]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[b]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[b]['date'] +"</div></div>");
4701
+                                           }
4702
+                                       }
4703
+                                  }
4704
+                                  var convDataPerNmbrpn = rowMessageArrpn.join("<br>");
4705
+                                  var crtNmber = fromtoNumberArr[k];
4706
+                                  var crtName = selectedNames[h];
4707
+                                  msgsNmbrsNames[crtNmber] = msgsNmbrsNames[crtNmber] || {};
4708
+                                  msgsNmbrsNames[crtNmber][crtName] = convDataPerNmbrpn;
4709
+                             }
4710
+
4711
+                             var rowMessageArr = [];
4712
+                             for (var m = 0; m < convData.length; m++) {
4713
+
4714
+                                  if (convData[m]['direction'] == 'sent_from') {
4715
+                                      if (convData[m]['status']) {
4716
+                                          if (convData[m]['status'].indexOf("delivered") > -1 || convData[m]['status'].indexOf("delivery success") > -1 || convData[m]['status'].indexOf("Retrieved") > -1) {
4717
+                                              var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
4718
+                                          } else {
4719
+                                              var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
4720
+                                          }
4721
+                                      } else {
4722
+                                          var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
4723
+                                      }
4724
+                                      rowMessageArr.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:inline-block;margin:6px 6px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
4725
+
4726
+                                  } else if (convData[m]['direction'] == 'sent_to') {
4727
+                                      if (convData[m]['status']) {
4728
+                                          if (convData[m]['status'].indexOf("delivered") > -1 || convData[m]['status'].indexOf("delivery success") > -1 || convData[m]['status'].indexOf("Retrieved") > -1) {
4729
+                                              var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/check.svg' title='`delivery success` received.'>";
4730
+                                          } else {
4731
+                                              var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
4732
+                                          }
4733
+                                      } else {
4734
+                                          var sentMsgStatus = "<img src='/" + ctappdir + "/sms_relentless/img/question.svg' title='This message did not receive a `delivery success` receipt. However, it is possible that it reached its destination.'>";
4735
+                                      }
4736
+                                      rowMessageArr.push("<div class='groupedSentMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;color:#06866f;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/outgoing.svg' title='Message sent to current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:inline-block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div><div class='sentMssgStatus'>"+ sentMsgStatus +"</div></div>");
4737
+
4738
+                                  } else if (convData[m]['direction'] == 'received_from') {
4739
+
4740
+		                      rowMessageArr.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received from current number.'></div><div style='display:inline-block;color:#06866f;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#353535;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div></div>");
4741
+
4742
+                                  } else if (convData[m]['direction'] == 'received_on') {
4743
+
4744
+		                      rowMessageArr.push("<div class='groupedRecMsg'><div style='display:block;margin:0px 0px 6px 0px;'><div style='display:inline-block;margin:0px 12px 0px 3px;'><img src='/" + ctappdir + "/sms_relentless/img/incoming.svg' title='Message received on current number.'></div><div style='display:inline-block;color:#353535;'>From: "+ convData[m]['from'] +"</div><div style='display:inline-block;margin:0px 0px 0px 12px;color:#06866f;'>To: "+ convData[m]['to'] +"</div></div><div style='display:block;font-size:14px;color:#353535;font-weight:500;'>"+ convData[m]['message'] +"</div><div style='display:block;margin:6px 0px 0px 4px;font-size:12.5px;color:#353535;'>"+ convData[m]['date'] +"</div></div>");
4745
+                                  }
4746
+                             }
4747
+
4748
+                             var convDataPerNmbr = rowMessageArr.join("");
4749
+
4750
+                             var rowPhoneNumber = "<div id='nmbrow_"+ fromtoNumberArr[k] +"' class='phoneNmbrRow'>"+ fromtoNumberArr[k] +"</div>";
4751
+
4752
+		             $("#groupedSmsTable").append("<tr id='singlerow_"+ k +"' class='groupedrowsbody'><td><div class='groupedLstNmbr fixedRowHeight'>"+ rowPhoneNumber +"</div></td><td><div class='groupedLstNames fixedRowHeight'>"+ displayNames +"</div></td><td style='width:100%'><div class='groupedLstMsgs fixedRowHeight'>"+ convDataPerNmbr +"</div></td></tr>");
4753
+                             $("#groupedSmsTable").append("<tr id='expandRow_"+ k +"' class='groupedrowsexp'><td colspan='3'><div style='display:block;width:100%;height:14px;cursor:pointer;'><img class='expandGrpRow' src='/" + ctappdir + "/sms_relentless/img/arrowDown.svg'></div><td></tr>");
4754
+
4755
+                             // Store the messages for the current number, to be able to see them later, when clicking on the number
4756
+                             var ctNmbr = fromtoNumberArr[k];
4757
+                             messagesPerNmbr[ctNmbr] = convDataPerNmbr;
4758
+                        }
4759
+
4760
+
4761
+                        // Add the 'filter by number' drop-down list
4762
+                        var nmbrslst = "<option value='title'>Filter messages by number</option>";
4763
+                        for (var p = 0; p < fromtoNumberArr.length; p++) {
4764
+                             nmbrslst += "<option value='"+ fromtoNumberArr[p] +"'>"+ fromtoNumberArr[p] +"</option>";
4765
+                        }
4766
+                        $("#filterByNumber").append("<select id='selectListedNmbrs'>"+ nmbrslst +"</select>");
4767
+
4768
+
4769
+                        $("#selectListedNmbrs").change(function() {
4770
+
4771
+                          var selectedNmbr = $(this).val();
4772
+
4773
+                          if (selectedNmbr != "title") {
4774
+
4775
+                              $(".groupedrowsbody,.groupedrowsexp").each(function() { $(this).hide(); });
4776
+		              $("#groupedSmsTable").append("<tr id='singlerowfl_"+ fromtoNumberArr.indexOf(selectedNmbr) +"' class='groupedrowsbody'><td><div class='groupedLstNmbr fixedRowHeight'><div id='nmbrow_"+ selectedNmbr +"' style='font-size:15px;font-weight:500;color:#06866f;cursor:pointer;'>"+ selectedNmbr +"</div></div></td><td><div class='groupedLstNames fixedRowHeight'>"+ msgsNamesPerNmbr[selectedNmbr] +"</div></td><td style='width:100%'><div class='groupedLstMsgs fixedRowHeight'>"+ messagesPerNmbr[selectedNmbr] +"</div></td></tr>");
4777
+                              $("#groupedSmsTable").append("<tr id='expandRowfl_"+ fromtoNumberArr.indexOf(selectedNmbr) +"' class='groupedrowsexp'><td colspan='3'><div style='display:block;width:100%;height:14px;cursor:pointer;'><img class='expandGrpRow' src='/" + ctappdir + "/sms_relentless/img/arrowDown.svg'></div><td></tr>");
4778
+
4779
+
4780
+                               // Show the messages sent by each user whose name is listed for the phone number of the current row
4781
+                               $('[id*="diplNm_"]').click(function() {
4782
+
4783
+                                  var crntNmbr = $(this).attr("id").split("_")[1];
4784
+                                  var crntDisName = $(this).attr("name");                        
4785
+                                  var clsmsgcell = $(this).closest(".groupedrowsbody").find(".groupedLstMsgs");
4786
+                                  clsmsgcell.empty();
4787
+                                  clsmsgcell.html(msgsNmbrsNames[crntNmbr][crntDisName]);
4788
+
4789
+                                  $(".dispNameList").each(function() { $(this).css("color", "#0a559e"); });
4790
+                                  $(this).css("color", "#1483f0");
4791
+                                  $("#nmbrow_"+ selectedNmbr).css("color", "#06866f");
4792
+                                  $(".groupedLstNmbr").each(function () { $(this).css("color", "#06866f"); });
4793
+                               });
4794
+
4795
+
4796
+		               // Show all the messages sent to/from the clicked number
4797
+		               $('[id*="nmbrow_"]').click(function() {
4798
+		                  var rwNmbr = $(this).attr("id").replace("nmbrow_", "");
4799
+		                  var rowmsgcell = $(this).closest(".groupedrowsbody").find(".groupedLstMsgs");
4800
+		                  rowmsgcell.empty();
4801
+		                  rowmsgcell.html(messagesPerNmbr[rwNmbr]);
4802
+
4803
+		                  $(".phoneNmbrRow").each(function() { $(this).css("color", "#06866f"); });
4804
+		                  $(".dispNameList").each(function() { $(this).css("color", "#0a559e"); });
4805
+		                  $(this).css("color", "#08b899");
4806
+		               });
4807
+
4808
+
4809
+		               // Expand the rows to see all the messages
4810
+		               $('[id^="expandRowfl_"]').click(function() {
4811
+		                   var idnumbrfl = $(this).attr("id").replace("expandRowfl_", "");
4812
+		                   var crntExpandfl = $(this).find(".expandGrpRow");
4813
+
4814
+		                   if (crntExpandfl.attr('src') == '/' + ctappdir + '/sms_relentless/img/arrowDown.svg') {
4815
+                                       $("#singlerowfl_"+ idnumbrfl).find(".fixedRowHeight").removeClass("fixedRowHeight");
4816
+		                       crntExpandfl.attr('src', '/' + ctappdir + '/sms_relentless/img/arrowUp.svg');
4817
+		                   } else {
4818
+                                       $("#singlerowfl_"+ idnumbrfl).find(".groupedLstNmbr,.groupedLstNames,.groupedLstMsgs").addClass("fixedRowHeight");
4819
+                                       crntExpandfl.attr('src', '/' + ctappdir + '/sms_relentless/img/arrowDown.svg'); 
4820
+		                   }
4821
+		               });
4822
+
4823
+		               $('#totalgrpmessages').remove();
4824
+		               $('#smstables').append("<div id='totalgrpmessages'>Total displayed phone numbers: 1</div>");
4825
+                           }
4826
+                        });
4827
+
4828
+                        // Clear the 'filter by number' filter
4829
+                        $("#cleargrpfilter").click(function() {
4830
+                               $('[id^="singlerowfl_"]').remove();
4831
+                               $('[id^="expandRowfl_"]').remove();
4832
+                               $(".groupedrowsbody,.groupedrowsexp").each(function() { $(this).show(); });
4833
+                               $("#selectListedNmbrs").val("title");
4834
+		               $('#totalgrpmessages').remove();
4835
+		               $('#smstables').append("<div id='totalgrpmessages'>Total displayed phone numbers: "+ totalPhNmbrs +"</div>");
4836
+                        });
4837
+
4838
+                        // Show the messages sent by each user whose name is listed for the phone number on the current row
4839
+                        $('[id*="diplNm_"]').click(function() {
4840
+
4841
+                           var crntNmbr = $(this).attr("id").split("_")[1];
4842
+                           var crntDisName = $(this).attr("name");                               
4843
+                           var clsmsgcell = $(this).closest(".groupedrowsbody").find(".groupedLstMsgs");
4844
+                           clsmsgcell.empty();
4845
+                           clsmsgcell.html(msgsNmbrsNames[crntNmbr][crntDisName]);
4846
+
4847
+                           $(".dispNameList").each(function() { $(this).css("color", "#0a559e"); });
4848
+                           $(this).css("color", "#1483f0");
4849
+                        });
4850
+
4851
+                        // Show all the messages sent to/from the clicked number
4852
+                        $('[id*="nmbrow_"]').click(function() {
4853
+                           var rwNmbr = $(this).attr("id").replace("nmbrow_", "");
4854
+                           var rowmsgcell = $(this).closest(".groupedrowsbody").find(".groupedLstMsgs");
4855
+                           rowmsgcell.empty();
4856
+                           rowmsgcell.html(messagesPerNmbr[rwNmbr]);
4857
+
4858
+                           $(".phoneNmbrRow").each(function() { $(this).css("color", "#06866f"); });
4859
+                           $(".dispNameList").each(function() { $(this).css("color", "#0a559e"); });
4860
+                           $(this).css("color", "#08b899");
4861
+                        });
4862
+
4863
+
4864
+		        $('#smstables').removeClass('icon-loading');
4865
+		        $('#recarrow').removeClass('arrowUpCl');
4866
+		        $('#recarrow').addClass('arrowDownCl');
4867
+
4868
+                        // Expand the rows to see all the messages
4869
+                        $('[id^="expandRow_"]').click(function() {
4870
+                            var idnumbr = $(this).attr("id").replace("expandRow_", "");
4871
+                            var crntExpand = $(this).find(".expandGrpRow");
4872
+
4873
+                            if (crntExpand.attr('src') == '/' + ctappdir + '/sms_relentless/img/arrowDown.svg') {
4874
+                                $("#singlerow_"+ idnumbr).find(".fixedRowHeight").removeClass("fixedRowHeight");
4875
+                                crntExpand.attr('src', '/' + ctappdir + '/sms_relentless/img/arrowUp.svg');
4876
+                            } else {
4877
+                                $("#singlerow_"+ idnumbr).find(".groupedLstNmbr,.groupedLstNames,.groupedLstMsgs").addClass("fixedRowHeight");
4878
+                                crntExpand.attr('src', '/' + ctappdir + '/sms_relentless/img/arrowDown.svg'); 
4879
+                            }
4880
+                        });
4881
+
4882
+
4883
+		        // Add pagination
4884
+		        var rowsShowngrp = messagesperpage;
4885
+		        var rowsTotalgrp = $("#groupedSmsTable tr").length;
4886
+
4887
+		        var numPagesgrp = ((rowsTotalgrp - 2) / rowsShowngrp) / 2;
4888
+
4889
+		        for (i = 0; i < numPagesgrp; i++) {
4890
+		             var pageNumgrp = i + 1;
4891
+		             $('#paginationgrp').append('<a href="#" rel="' + i + '" class="pagenumbersgrp">' + pageNumgrp + '</a> ');
4892
+		        }
4893
+
4894
+		        $('#paginationgrp').children(":first").addClass('active');
4895
+
4896
+		        $(".groupedrowsbody,.groupedrowsexp").hide();
4897
+
4898
+		        $('#paginationgrp a:first').addClass('active');
4899
+
4900
+		        // Show table page when clicking a page number
4901
+		        $('.grppages a').bind('click', function() {
4902
+
4903
+		           $('#paginationgrp').children().removeClass('active');
4904
+
4905
+		           $(this).addClass('active');
4906
+
4907
+		           var currentPageNogrp = $(this).text();
4908
+
4909
+		           $('#paginationgrp a').each(function() {
4910
+		               if ($(this).text() == currentPageNogrp) {
4911
+		                   $(this).addClass('active');
4912
+		               }
4913
+		           });
4914
+
4915
+		           var currPagegrp = $(this).attr('rel');
4916
+		           var startItemgrp = currPagegrp * rowsShowngrp;
4917
+		           var endItemgrp = startItemgrp + rowsShowngrp;
4918
+
4919
+		           $(".groupedrowsbody").hide().slice(startItemgrp, endItemgrp).css('display', 'table-row');
4920
+		           $(".groupedrowsexp").hide().slice(startItemgrp, endItemgrp).css('display', 'table-row');
4921
+
4922
+		           $('#totalgrpmessages').remove();
4923
+		           $('#smstables').append("<div id='totalgrpmessages'>Total displayed phone numbers: " + totalPhNmbrs + "</div>");
4924
+		        });
4925
+
4926
+                        $('#paginationgrp').children(":last").trigger('click');
4927
+
4928
+
4929
+		        // Show/Hide filter row
4930
+		        $('#recarrow').on('click', function() {
4931
+			   if ($('#grpfiltersrow').is(':visible')) {
4932
+			       $('#grpfiltersrow').hide();
4933
+		               $('#grpheaderrow').css('top', '0px');
4934
+		               $(this).removeClass('arrowUpCl');
4935
+		               $(this).addClass('arrowDownCl');
4936
+			   } else {
4937
+			       $('#grpfiltersrow').show();
4938
+		               $('#grpheaderrow').css('top', '158px');
4939
+		               $(this).removeClass('arrowDownCl');
4940
+		               $(this).addClass('arrowUpCl');
4941
+		           }
4942
+		        });
4943
+
4944
+
4945
+		        // Download MMS files when clicking on their URLs
4946
+		        $('[id^="mmsTblUrl-"]').on('click', function(evt) {
4947
+
4948
+		           var clckedUrl = $(this).text();
4949
+		           var flNamearr = clckedUrl.split("/");
4950
+		           var flName = flNamearr.reverse()[0];
4951
+
4952
+		           confirmAlert("Download this file only if you trust the sender and the domain of the URL.");
4953
+
4954
+			   $("#confirmOk").click(function() {
4955
+
4956
+		              $("#alertMsgOverlay").remove();
4957
+			      $("#alertConfMessage").remove();
4958
+
4959
+			      var mmsLink = document.createElement("a");
4960
+			      mmsLink.setAttribute('href', clckedUrl);
4961
+			      mmsLink.setAttribute('download', flName);
4962
+                              mmsLink.setAttribute('target', '_blank');
4963
+			      document.body.appendChild(mmsLink);
4964
+			      mmsLink.click();
4965
+			      mmsLink.remove();
4966
+		           });
4967
+
4968
+			   $("#confirmCancel").click(function() { $("#alertMsgOverlay").remove(); $("#alertConfMessage").remove(); });
4969
+		        });
4970
+
4971
+          },
4972
+          error: function() {
4973
+
4974
+                        showAlert("Error while attempting to get the messages from the database.");
4975
+                        $('#smstables').removeClass('icon-loading');
4976
+          }
4977
+     });
4978
+
4979
+     // Stop auto-refreshing the page and hide the auto-refresh button
4980
+     if ($("#stopAutoRefreshSentBtn").text() == "Stop auto refresh") { $("#stopAutoRefreshSentBtn").click(); }
4981
+
4982
+     $("#stopAutoRefreshSent").css("display", "none");
4983
+  });
4984
+
4985
+
4986
+  function showAlert(alertText) {
4987
+
4988
+     let alertwnd = "<div id='alertMessage'>";
4989
+     alertwnd += "<a id='closeAlertWnd' title='Close this window'></a>";
4990
+     alertwnd += "<div id='alertTextWrap'>"+ alertText +"</div>";
4991
+     alertwnd += "<input type='submit' id='alertOk' value='OK'>";
4992
+     alertwnd += "</div>";
4993
+
4994
+     $("#content").append("<div id='alertMsgOverlay'></div>");
4995
+     $("#content").append(alertwnd);
4996
+
4997
+     let topDist = parseInt((window.innerHeight / 2).toFixed(2) - 152) +"px";
4998
+     let leftDist = parseInt((window.innerWidth / 2).toFixed(2) - 150) +"px";
4999
+     $("#alertMessage").css({ "top" : topDist, "left" : leftDist });
5000
+
5001
+     $("#closeAlertWnd").click(function() { $("#alertMsgOverlay").remove(); $("#alertMessage").remove(); });
5002
+     $("#alertMsgOverlay").click(function() { $("#alertMsgOverlay").remove(); $("#alertMessage").remove(); });
5003
+     $("#alertOk").click(function() { $("#alertMsgOverlay").remove(); $("#alertMessage").remove(); });
5004
+  }
5005
+
5006
+  function confirmAlert(alertText) {
5007
+
5008
+     $("#alertMsgOverlay").remove();
5009
+     $("#alertConfMessage").remove();
5010
+
5011
+     let alertwndcf = "<div id='alertConfMessage'>";
5012
+     alertwndcf += "<a id='closeAlertWndcf' title='Close this window'></a>";
5013
+     alertwndcf += "<div id='alertTextWrap'>"+ alertText +"</div>";
5014
+     alertwndcf += "<div id='cancelOkWrap'><input type='submit' id='confirmCancel' value='Cancel'>";
5015
+     alertwndcf += "<input type='submit' id='confirmOk' value='OK'></div>";
5016
+     alertwndcf += "</div>";
5017
+
5018
+     $("#content").append("<div id='alertMsgOverlay'></div>");
5019
+     $("#content").append(alertwndcf);
5020
+
5021
+     let topDist = parseInt((window.innerHeight / 2).toFixed(2) - 152) +"px";
5022
+     let leftDist = parseInt((window.innerWidth / 2).toFixed(2) - 150) +"px";
5023
+     $("#alertConfMessage").css({ "top" : topDist, "left" : leftDist });
5024
+
5025
+     $("#closeAlertWndcf").click(function() { $("#alertMsgOverlay").remove(); $("#alertConfMessage").remove(); });
5026
+     $("#alertMsgOverlay").click(function() { $("#alertMsgOverlay").remove(); $("#alertConfMessage").remove(); });
5027
+  }
5028
+
5029
+
5030
+  // Append the auto-refresh button that refreshes the 'Sent SMS Messages' page
5031
+  $("#app-content").append("<div id='stopAutoRefreshSent'><div id='stopAutoRefreshSentBtn'>Start auto refresh</div><div id='refreshTimerSent' class='arftimer' style='--duration: 15;--size: 24;'><div class='arfmask'></div></div></div>");
5032
+
5033
+  $("#stopAutoRefreshSentBtn").click(function() {
5034
+     if ($("#stopAutoRefreshSentBtn").text() == "Stop auto refresh") {
5035
+         clearInterval(intervalRfrSent);
5036
+         $("#stopAutoRefreshSentBtn").text("Start auto refresh");
5037
+         $("#stopAutoRefreshSentBtn").css("color", "#0a559e");
5038
+         $("#refreshTimerSent").css("display", "none");
5039
+     } else {
5040
+         clearInterval(intervalRfrSent);
5041
+         intervalRfrSent = setInterval(function() { $("#sentsmstableshow").click(); }, 15000);
5042
+         $("#stopAutoRefreshSentBtn").text("Stop auto refresh");
5043
+         $("#stopAutoRefreshSentBtn").css("color", "#04957b");
5044
+         $("#refreshTimerSent").css("display", "inline-block");
5045
+     }
5046
+  });
5047
+
5048
+});
0 5049
new file mode 100644
... ...
@@ -0,0 +1,15 @@
1
+OC.L10N.register(
2
+    "sms_relentless",
3
+    {
4
+    "Settings" : "Settings",
5
+    "SMS Relentless" : "SMS Relentless",
6
+    "Enter your credentials and options in the fields from below. As SMS service provider you can use Telnyx, Plivo, Twilio or Flowroute, or all of them:" : "Enter your credentials and options in the fields from below. As SMS service provider you can use Telnyx, Plivo, Twilio or Flowroute, or all of them:",
7
+    "Generate new webhook URL for incoming SMS" : "Generate new webhook URL for incoming SMS",
8
+    "Generate new webhook URL for delivery receipts" : "Generate new webhook URL for delivery receipts",
9
+    "Generate new webhook URL for incoming SMS" : "Generate new webhook URL for incoming SMS",
10
+    "Generate new webhook URL for delivery receipts" : "Generate new webhook URL for delivery receipts",
11
+    "Save" : "Save",
12
+    "New SMS message" : "New SMS message",
13
+    "New SMS message from SMS Relentless" : "New SMS message from SMS Relentless"
14
+},
15
+"nplurals=2; plural=(n != 1);");
0 16
new file mode 100644
... ...
@@ -0,0 +1,13 @@
1
+{ "translations": {
2
+    "Settings" : "Settings",
3
+    "SMS Relentless" : "SMS Relentless",
4
+    "Enter your credentials and options in the fields from below. As SMS service provider you can use Telnyx, Plivo, Twilio or Flowroute, or all of them:" : "Enter your credentials and options in the fields from below. As SMS service provider you can use Telnyx, Plivo, Twilio or Flowroute, or all of them:",
5
+    "Generate new webhook URL for incoming SMS" : "Generate new webhook URL for incoming SMS",
6
+    "Generate new webhook URL for delivery receipts" : "Generate new webhook URL for delivery receipts",
7
+    "Generate new webhook URL for incoming SMS" : "Generate new webhook URL for incoming SMS",
8
+    "Generate new webhook URL for delivery receipts" : "Generate new webhook URL for delivery receipts",
9
+    "Save" : "Save",
10
+    "New SMS message" : "New SMS message",
11
+    "New SMS message from SMS Relentless" : "New SMS message from SMS Relentless"
12
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
13
+}
0 14
new file mode 100644
... ...
@@ -0,0 +1,15 @@
1
+OC.L10N.register(
2
+    "sms_relentless",
3
+    {
4
+    "Settings" : "Settings",
5
+    "SMS Relentless" : "SMS Relentless",
6
+    "Enter your credentials and options in the fields from below. As SMS service provider you can use Telnyx, Plivo, Twilio or Flowroute, or all of them:" : "Enter your credentials and options in the fields from below. As SMS service provider you can use Telnyx, Plivo, Twilio or Flowroute, or all of them:",
7
+    "Generate new webhook URL for incoming SMS" : "Generate new webhook URL for incoming SMS",
8
+    "Generate new webhook URL for delivery receipts" : "Generate new webhook URL for delivery receipts",
9
+    "Generate new webhook URL for incoming SMS" : "Generate new webhook URL for incoming SMS",
10
+    "Generate new webhook URL for delivery receipts" : "Generate new webhook URL for delivery receipts",
11
+    "Save" : "Save",
12
+    "New SMS message" : "New SMS message",
13
+    "New SMS message from SMS Relentless" : "New SMS message from SMS Relentless"
14
+},
15
+"nplurals=2; plural=(n != 1);");
0 16
new file mode 100644
... ...
@@ -0,0 +1,13 @@
1
+{ "translations": {
2
+    "Settings" : "Settings",
3
+    "SMS Relentless" : "SMS Relentless",
4
+    "Enter your credentials and options in the fields from below. As SMS service provider you can use Telnyx, Plivo, Twilio or Flowroute, or all of them:" : "Enter your credentials and options in the fields from below. As SMS service provider you can use Telnyx, Plivo, Twilio or Flowroute, or all of them:",
5
+    "Generate new webhook URL for incoming SMS" : "Generate new webhook URL for incoming SMS",
6
+    "Generate new webhook URL for delivery receipts" : "Generate new webhook URL for delivery receipts",
7
+    "Generate new webhook URL for incoming SMS" : "Generate new webhook URL for incoming SMS",
8
+    "Generate new webhook URL for delivery receipts" : "Generate new webhook URL for delivery receipts",
9
+    "Save" : "Save",
10
+    "New SMS message" : "New SMS message",
11
+    "New SMS message from SMS Relentless" : "New SMS message from SMS Relentless"
12
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
13
+}
0 14
new file mode 100644
... ...
@@ -0,0 +1,1146 @@
1
+<?php
2
+/**
3
+ * @copyright 2021 Double Bastion LLC <www.doublebastion.com>
4
+ *
5
+ * @author Double Bastion LLC
6
+ *
7
+ * @license GNU AGPL version 3 or any later version
8
+ *
9
+ * This program is free software; you can redistribute it and/or
10
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
11
+ * License as published by the Free Software Foundation; either
12
+ * version 3 of the License, or any later version.
13
+ *
14
+ * This program is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
18
+ *
19
+ * You should have received a copy of the GNU Affero General Public
20
+ * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
+ *
22
+ */
23
+
24
+declare(strict_types=1);
25
+
26
+namespace OCA\SMSRelentless\Controller;
27
+
28
+use OCP\IRequest;
29
+use OCP\AppFramework\Controller;
30
+use OCA\SMSRelentless\Service\SmsrelentlessService;
31
+use OCP\AppFramework\App;
32
+use OC\Http\Client\Client;
33
+use OCP\Files\SimpleFS\ISimpleFile;
34
+use OCP\Files\SimpleFS\ISimpleFolder;
35
+use OCP\IL10N;
36
+use OCP\Files\Folder;
37
+use OCP\IConfig;
38
+use OC\Files\Filesystem;
39
+use OC\Files\View;
40
+use \ReflectionClass;
41
+use \FilesystemIterator;
42
+use \DateTime;
43
+use \DateInterval;
44
+use OCP\AppFramework\Http\DataResponse;
45
+use OCP\Files\NotFoundException;
46
+use OCP\Files\NotPermittedException;
47
+use Plivo\RestClient;
48
+use OCP\Share\IManager;
49
+use OCP\Constants;
50
+use OCP\IGroupManager;
51
+use OCP\IDBConnection;
52
+use OCP\IUserManager;
53
+use OC\URLGenerator;
54
+
55
+class SmsrelentlessController extends Controller {
56
+
57
+    private $service;
58
+    private $config;
59
+    private $userId;
60
+    private $folder;
61
+    private $filesystem;
62
+    private $view;
63
+    private $shareManager;
64
+    private $groupManager;
65
+    private $connection;
66
+    private $userManager;
67
+    private $urlGenerator;
68
+
69
+    public function __construct($appName, IRequest $request, SmsrelentlessService $service, IConfig $config, $userId, Folder $folder, Filesystem $filesystem, View $view, IManager $shareManager, IGroupManager $groupManager, IDBConnection $connection, IUserManager $userManager, URLGenerator $urlGenerator) {
70
+        parent::__construct($appName, $request);
71
+        $this->service = $service;
72
+        $this->config = $config;
73
+        $this->userId = $userId;
74
+        $this->folder = $folder;
75
+        $this->filesystem = $filesystem;
76
+        $this->view = $view;
77
+	$this->shareManager = $shareManager;
78
+        $this->groupManager = $groupManager;
79
+        $this->connection = $connection;
80
+        $this->userManager = $userManager;
81
+        $this->urlGenerator = $urlGenerator;
82
+    }
83
+
84
+
85
+    /**
86
+     * @NoAdminRequired
87
+     */
88
+    public function object_to_array($obj) {
89
+        if (is_object($obj)) $obj = (array)$this->dismount($obj);
90
+        if (is_array($obj)) {
91
+           $new = array();
92
+           foreach($obj as $key => $val) {
93
+               $new[$key] = $this->object_to_array($val);
94
+           }
95
+        }
96
+        else $new = $obj;
97
+        return $new;
98
+    }
99
+
100
+
101
+    /**
102
+     * @NoAdminRequired
103
+     */
104
+    public function dismount($object) {
105
+        $reflectionClass = new ReflectionClass(get_class($object));
106
+        $array = array();
107
+        foreach ($reflectionClass->getProperties() as $property) {
108
+           $property->setAccessible(true);
109
+           $array[$property->getName()] = $property->getValue($object);
110
+           $property->setAccessible(false);
111
+        }
112
+        return $array;
113
+    }
114
+
115
+
116
+    /**
117
+     * @NoAdminRequired
118
+     */
119
+    public function getappdirectory($userId) {
120
+        $apprelpath = $this->urlGenerator->linkTo('sms_relentless', 'COPYING.txt');
121
+        $apprelpatharr = explode("/", $apprelpath);
122
+        $currentappdir = $apprelpatharr[1];
123
+        return $currentappdir;
124
+    }
125
+
126
+
127
+    /**
128
+     * @NoAdminRequired
129
+     */
130
+    public function getbalancetel($userId) {
131
+
132
+        $telsmsapicred = $this->service->getapicredentials($this->userId);
133
+
134
+        $telapikey = $telsmsapicred[0];
135
+        $ch = curl_init();
136
+        $headerstel = array("Content-Type: application/json", "Accept: application/json", "Authorization: Bearer ".$telapikey);
137
+
138
+        curl_setopt($ch, CURLOPT_URL, "https://api.telnyx.com/v2/balance");
139
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
140
+        curl_setopt($ch, CURLOPT_HTTPHEADER, $headerstel);
141
+        $responsetel = curl_exec($ch);
142
+        $recdatatel = json_decode($responsetel, TRUE);
143
+        $telbalresponse = $recdatatel['data']['balance'];
144
+        $currentbalancetel = round(floatval($telbalresponse), 3);
145
+        curl_close($ch);
146
+
147
+        return $currentbalancetel;
148
+    }
149
+
150
+
151
+    /**
152
+     * @NoAdminRequired
153
+     */
154
+    public function getbalancenex($userId) {
155
+
156
+        $smsapicred = $this->service->getapicredentials($this->userId);
157
+        $smsapikey = $smsapicred[5];
158
+        $smsapisecret = $smsapicred[6];
159
+
160
+        if ($smsapikey == '' || $smsapisecret == '') {
161
+            $currentbalancenex = "N/A";
162
+        } else {
163
+            $getmesdata = "https://".$smsapikey.":".$smsapisecret."@api.plivo.com/v1/Account/".$smsapikey."/";
164
+            $mesdata = file_get_contents($getmesdata);
165
+            $datainit = json_decode($mesdata);
166
+            $balancenex = $datainit->cash_credits;
167
+            $currentbalancenex = round(floatval($balancenex), 3);
168
+        }
169
+        return $currentbalancenex;
170
+    }
171
+
172
+
173
+    /**
174
+     * @NoAdminRequired
175
+     */
176
+    public function getbalancetwil($userId) {
177
+
178
+        $smsapicred = $this->service->getapicredentials($this->userId);
179
+        $smsapisid = $smsapicred[15];
180
+        $smsapitoken = $smsapicred[16];
181
+
182
+        if ($smsapisid == '' || $smsapitoken == '') {
183
+            $currentbalancetwil = "N/A";
184
+        } else {
185
+
186
+            $twilbalance = json_decode(file_get_contents("https://".$smsapisid.":".$smsapitoken."@api.twilio.com/2010-04-01/Accounts/".$smsapisid."/Balance.json"));
187
+            $balancetwil = $twilbalance->balance;
188
+
189
+            $currentbalancetwil = round(floatval($balancetwil), 3);
190
+        }
191
+        return $currentbalancetwil;
192
+    }
193
+
194
+
195
+    /**
196
+     * @NoAdminRequired
197
+     */
198
+    public function getbalanceflow($userId) {
199
+
200
+        $currentbalanceflow = 'n/a';
201
+        return $currentbalanceflow;
202
+    }
203
+
204
+
205
+    /**
206
+     * @NoAdminRequired
207
+     */
208
+    public function getsmsnumbers($userId) {
209
+
210
+        return $this->service->getsmsnumbers($this->userId);
211
+    }
212
+
213
+
214
+    /**
215
+     * @NoAdminRequired
216
+     */
217
+    public function refreshavailablenumbers($userId) {
218
+
219
+        return $this->service->refreshavailablenumbers($this->userId);
220
+    }
221
+
222
+
223
+    /**
224
+     * @NoAdminRequired
225
+     */
226
+    public function cleantempdir($userId) {
227
+
228
+        // Create the temporary folder if it doesn't exist
229
+        if ($this->folder->nodeExists('SMS_Relentless/temp_files') == false) {
230
+            $this->folder->newFolder('SMS_Relentless/temp_files');
231
+        }
232
+        $datadir = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/';
233
+        $targetdir = $datadir . $this->userId . "/files/SMS_Relentless/temp_files";
234
+        $fileSystemIterator = new FilesystemIterator($targetdir);
235
+
236
+        $dirfiles = [];
237
+        foreach ($fileSystemIterator as $fileInfo) {
238
+                 $dirfiles[] = $fileInfo->getFilename();
239
+        }
240
+
241
+        foreach ($dirfiles as $key => $indfile) {
242
+                 $thisuserroot = $this->view->getRoot();
243
+                 $tempfile = $thisuserroot . "/SMS_Relentless/temp_files/" . $indfile;
244
+                 $removetmpfile = $this->filesystem->unlink($tempfile);
245
+        }
246
+     }
247
+
248
+
249
+    /**
250
+     * @NoAdminRequired
251
+     */
252
+    public function cleanmultrecdir($userId) {
253
+
254
+        // Create the temporary folder if it doesn't exist
255
+        if ($this->folder->nodeExists('SMS_Relentless/multiple_recipients') == false) {
256
+            $this->folder->newFolder('SMS_Relentless/multiple_recipients');
257
+        }
258
+        $datadirmrc = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/';
259
+        $targetdirmrc = $datadirmrc . $this->userId . "/files/SMS_Relentless/multiple_recipients";
260
+        $fileSystemIteratormrc = new FilesystemIterator($targetdirmrc);
261
+
262
+        $dirfilesmrc = [];
263
+        foreach ($fileSystemIteratormrc as $fileInfomrc){
264
+                 $dirfilesmrc[] = $fileInfomrc->getFilename();
265
+        }
266
+
267
+        foreach ($dirfilesmrc as $mreckey => $mrecfile) {
268
+                 $thisuserrootmrc = $this->view->getRoot();
269
+                 $mrectempfile = $thisuserrootmrc . "/SMS_Relentless/multiple_recipients/" . $mrecfile;
270
+                 $removemrectmpfile = $this->filesystem->unlink($mrectempfile);
271
+        }
272
+     }
273
+
274
+
275
+    /**
276
+     * @NoAdminRequired
277
+     */
278
+    public function uploadNumbersFile($userId, $uploadfileforsms) {
279
+
280
+        // Create the temporary folder if it doesn't exist
281
+        if ($this->folder->nodeExists('SMS_Relentless/multiple_recipients') == false) {
282
+            $this->folder->newFolder('SMS_Relentless/multiple_recipients');
283
+        }
284
+
285
+        // First delete any file that has been previously uploaded
286
+        $datadir = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/';
287
+        $targetdir = $datadir . $this->userId . "/files/SMS_Relentless/multiple_recipients";
288
+        $fileSystemIterator = new FilesystemIterator($targetdir);
289
+
290
+        $dirfiles = [];
291
+        foreach ($fileSystemIterator as $fileInfo){
292
+                 $dirfiles[] = $fileInfo->getFilename();
293
+        }
294
+
295
+        foreach ($dirfiles as $key => $indfile) {
296
+                 $thisuserroot = $this->view->getRoot();
297
+                 $tempfile = $thisuserroot . "/SMS_Relentless/multiple_recipients/" . $indfile;
298
+                 $removetmpfile = $this->filesystem->unlink($tempfile);
299
+        }
300
+
301
+        // Upload the new file
302
+        $fileContent = file_get_contents($_FILES['uploadfileforsms']['tmp_name']);
303
+        $fileName = $_FILES['uploadfileforsms']['name'];
304
+
305
+        $userroot = $this->view->getRoot();
306
+        $targetfile = $userroot . "/SMS_Relentless/multiple_recipients/" . $fileName;
307
+
308
+        $target = $this->folder->newFile($targetfile);
309
+        $target->putContent($fileContent);
310
+
311
+        // Extract the phone numbers from the file
312
+        $numberarraysec = str_replace(array(";", "|", "\r\n", "\r", "\n", "\t"), ",", $fileContent);
313
+        $numberarraytert = preg_replace("/[^0-9,]/", "", $numberarraysec);
314
+        $numberarrayfourth = explode(",", $numberarraytert);
315
+        $numberarrayfifth = array_filter(array_map('trim', $numberarrayfourth));
316
+        $numberarray = array_unique($numberarrayfifth);
317
+
318
+        return $numberarray;
319
+    }
320
+
321
+
322
+    /**
323
+     * @NoAdminRequired
324
+     */
325
+    public function uploadfile($uploadfileformms) {
326
+
327
+           $fileContent = file_get_contents($_FILES['uploadfileformms']['tmp_name']);
328
+           $fileName = $_FILES['uploadfileformms']['name'];
329
+           $fileSizeinit = $_FILES['uploadfileformms']['size'];
330
+           $fileSize = $fileSizeinit / 1024;
331
+
332
+           if ($this->folder->nodeExists('SMS_Relentless/temp_files') == false) {
333
+               $this->folder->newFolder('SMS_Relentless/temp_files');
334
+           }
335
+
336
+           $userroot = $this->view->getRoot();
337
+           $targetfile = $userroot . "/SMS_Relentless/temp_files/" . $fileName;
338
+
339
+           $target = $this->folder->newFile($targetfile);
340
+           $target->putContent($fileContent);
341
+
342
+           // Get the cumulative files size of the uploaded files
343
+           $datadir = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/';
344
+           $targetdir = $datadir . $this->userId . "/files/SMS_Relentless/temp_files";
345
+
346
+           $fileSystemIterator = new FilesystemIterator($targetdir);
347
+
348
+           $dirfiles = [];
349
+           foreach ($fileSystemIterator as $fileInfo){
350
+                    $dirfiles[] = $fileInfo->getFilename();
351
+           }
352
+
353
+           $totalflsizeinit = 0;
354
+           foreach ($dirfiles as $key => $indfile) {
355
+                    $fileSizeinit = $this->filesystem->filesize($userroot . "/SMS_Relentless/temp_files/" . $indfile);
356
+                    $mbSize = round($fileSizeinit / 1024, 4);
357
+                    $totalflsizeinit += $mbSize;
358
+           }
359
+
360
+           $totalflsize = round($totalflsizeinit, 4);
361
+
362
+           return $totalflsize;
363
+    }
364
+
365
+
366
+    /**
367
+     * @NoAdminRequired
368
+     */
369
+    public function pickfile($path) {
370
+
371
+           if ($this->folder->nodeExists('SMS_Relentless/temp_files') == false) {
372
+               $this->folder->newFolder('SMS_Relentless/temp_files');
373
+           }
374
+
375
+           $datadir = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/';
376
+
377
+           $fltgt = $datadir . $this->userId . "/files" . $path;
378
+
379
+           $fileContent = file_get_contents($fltgt);
380
+
381
+           $pkfilesize = round(filesize($fltgt) / 1024, 4);
382
+
383
+           $patharr = explode("/", $path);
384
+
385
+           $revarr = array_reverse($patharr);
386
+
387
+           $relflpath = "/SMS_Relentless/temp_files/" . $revarr[0]; 
388
+
389
+           $target = $this->folder->newFile($relflpath);
390
+
391
+           $target->putContent($fileContent);
392
+
393
+           // Get the cumulative files size of the uploaded files
394
+           $targetdir = $datadir . $this->userId . "/files/SMS_Relentless/temp_files";
395
+
396
+           $fileSystemIterator = new FilesystemIterator($targetdir);
397
+
398
+           $dirfiles = [];
399
+           foreach ($fileSystemIterator as $fileInfo) {
400
+                    $dirfiles[] = $fileInfo->getFilename();
401
+           }
402
+
403
+           $totalflsizeinit = 0;
404
+
405
+           foreach ($dirfiles as $key => $indfile) {
406
+
407
+                    $fileSizeinit = $this->filesystem->filesize("/SMS_Relentless/temp_files/" . $indfile);
408
+                    $mbSize = round($fileSizeinit / 1024, 4);
409
+                    $totalflsizeinit += $mbSize;
410
+           }
411
+
412
+           $totalflsize = round($totalflsizeinit, 4);
413
+
414
+           $pickresult = [$totalflsize, $pkfilesize];
415
+
416
+           return $pickresult;
417
+    }
418
+
419
+
420
+    /**
421
+     * @NoAdminRequired
422
+     */
423
+    public function removeupfile($removedfilename) {
424
+
425
+           $tmpfl = "/" . $this->userId . "/files/SMS_Relentless/temp_files/" . $removedfilename;
426
+
427
+           $removefile = $this->view->unlink($tmpfl);
428
+
429
+           // Get the cumulative files size of the uploaded files
430
+           $datadir = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/';
431
+           $targetdir = $datadir . $this->userId . "/files/SMS_Relentless/temp_files";
432
+           $fileSystemIterator = new FilesystemIterator($targetdir);
433
+
434
+           $dirfiles = [];
435
+           foreach ($fileSystemIterator as $fileInfo){
436
+                    $dirfiles[] = $fileInfo->getFilename();
437
+           }
438
+
439
+           $totalflsizeinit = 0;
440
+
441
+           foreach ($dirfiles as $key => $indfile) {
442
+                    $fileSizeinit = $this->filesystem->filesize("/SMS_Relentless/temp_files/" . $indfile);
443
+                    $mbSize = round($fileSizeinit / 1024, 4);
444
+                    $totalflsizeinit += $mbSize;
445
+           }
446
+
447
+           $totalflsize = round($totalflsizeinit, 4);
448
+
449
+           return $totalflsize;
450
+    }
451
+
452
+
453
+    /**
454
+     * @NoAdminRequired
455
+     */
456
+    public function sendsmstel($userId, $receiversPhoneNbs, $fromsender, $waitinterval, $sentsmstext, $ismms, $mmsfiles) {
457
+
458
+         $telsmsapicred = $this->service->getapicredentials($this->userId);
459
+         $telnyxkey = $telsmsapicred[0];
460
+         $teldelrecurl = $telsmsapicred[3];
461
+         $messagingprofid = $telsmsapicred[4];
462
+         $addDisplName = $telsmsapicred[24];
463
+
464
+         // Get the Display Name of the current user
465
+         $crtuser = $this->userManager->get($this->userId);
466
+         $displayname = $crtuser->getDisplayName();
467
+
468
+         if ($addDisplName == 1) {
469
+             $sentsmstext = $displayname . ": " . $sentsmstext;
470
+         }
471
+
472
+         \Telnyx\Telnyx::setApiKey($telnyxkey);
473
+
474
+         $microinterval = $waitinterval * 1000;
475
+
476
+         foreach ($receiversPhoneNbs as $keytel => $tonumber) {
477
+
478
+             usleep($microinterval);
479
+
480
+             $messagedate = date("Y-m-d H:i:s");
481
+
482
+             if ($ismms == 0) {
483
+
484
+                 if (preg_match('/[A-Za-z]+/', $fromsender)) {
485
+                     $message = \Telnyx\Message::Create(["from" => $fromsender, "to" => $tonumber, "text" => $sentsmstext, "webhook_url" => $teldelrecurl, "messaging_profile_id" => $messagingprofid]);
486
+                 } else {
487
+                     $message = \Telnyx\Message::Create(["from" => $fromsender, "to" => $tonumber, "text" => $sentsmstext, "webhook_url" => $teldelrecurl]);
488
+                 }
489
+
490
+                 $messagetexttel = $sentsmstext;
491
+
492
+             } else {
493
+
494
+                 $mediaURLarr = [];
495
+                 $includedMediaFiles = '';
496
+
497
+                 for ($p = 0; $p < count($mmsfiles); $p++ ) {
498
+
499
+                      $userroot = $this->view->getRoot();
500
+                      $filetoshare = $userroot . "/SMS_Relentless/temp_files/".$mmsfiles[$p]."";
501
+
502
+                      $flsharetarget = $this->folder->newFile($filetoshare);
503
+
504
+	              $share = $this->shareManager->newShare();
505
+	              $share->setNode($flsharetarget);
506
+	              $share->setPermissions(Constants::PERMISSION_READ);
507
+	              $share->setShareType(\OC\Share\Constants::SHARE_TYPE_LINK);
508
+	              $share->setSharedBy($this->userId);
509
+                      $expirydate = DateTime::createFromFormat('Y-m-d H:i:s', $messagedate);
510
+                      $expirydate->add(new \DateInterval('P1D'));
511
+                      $share->setExpirationDate($expirydate);
512
+                      $shared = $this->shareManager->createShare($share);
513
+                      $shareToken = $shared->getToken();
514
+
515
+                      $hostnm = $_SERVER['REQUEST_SCHEME'] . "://" . $_SERVER['HTTP_HOST'];
516
+
517
+                      $mediaURLarr[] = $hostnm . "/s/" . $shareToken . "/download/" . $mmsfiles[$p];
518
+
519
+                      $includedMediaFiles .= "<div id='mmsTblUrl-" . mt_rand(1, 10000) . "' class='mmstblUrls' title='Download this file only if you trust the sender and the domain of the URL.'>" . $hostnm . "/s/" . $shareToken . "/download/" . $mmsfiles[$p] . "</div><br><br>";
520
+                 }
521
+
522
+                 if (preg_match('/[A-Za-z]+/', $fromsender)) {
523
+                     $message = \Telnyx\Message::Create(["from" => $fromsender, "to" => $tonumber, "text" => $sentsmstext, "webhook_url" => $teldelrecurl, "messaging_profile_id" => $messagingprofid, "subject" => "MMS", "media_urls" => $mediaURLarr]);
524
+                 } else {
525
+                     $message = \Telnyx\Message::Create(["from" => $fromsender, "to" => $tonumber, "text" => $sentsmstext, "webhook_url" => $teldelrecurl, "subject" => "MMS", "media_urls" => $mediaURLarr]);
526
+                 }
527
+
528
+                 $messagetexttel = $sentsmstext . "<br><br><br>--- File(s) included in MMS ---<br><br>" . $includedMediaFiles;
529
+             }
530
+
531
+             $messageid = $message['id'];
532
+             $messagefrom = "Telnyx: " . $fromsender;
533
+             $messageto = $tonumber;
534
+             $messagenetwork = null;
535
+             $messageprice = null;
536
+             $messagestatus = $message['to'][0]['status'];
537
+             $messagedelivery = null;
538
+
539
+             $sentmessagearr = [$messageid, $messagedate, $messagefrom, $messageto, $messagenetwork, $messageprice, $messagestatus, $messagedelivery, $messagetexttel];
540
+
541
+             $this->service->insertsentsms($this->userId, $displayname, $sentmessagearr);
542
+         }
543
+         return $displayname;
544
+    }
545
+
546
+
547
+    /**
548
+     * @NoAdminRequired
549
+     */
550
+    public function sendsmsnex($userId, $receiversPhoneNbs, $fromsender, $waitinterval, $sentsmstext, $ismms, $mmsfiles) {
551
+
552
+         $plsmsapicred = $this->service->getapicredentials($this->userId);
553
+
554
+         $smsapikey = $plsmsapicred[5];
555
+         $smsapisecret = $plsmsapicred[6];
556
+         $smsapideliveryrecurl = $plsmsapicred[8];
557
+         $addDisplName = $plsmsapicred[24];
558
+
559
+         // Get the Display Name of the current user
560
+         $crtuser = $this->userManager->get($this->userId);
561
+         $displayname = $crtuser->getDisplayName();
562
+
563
+         if ($addDisplName == 1) {
564
+             $sentsmstext = $displayname . ": " . $sentsmstext;
565
+         }
566
+
567
+         $microinterval = $waitinterval * 1000;
568
+
569
+         foreach ($receiversPhoneNbs as $keynex => $tonumber) {
570
+
571
+             usleep($microinterval);
572
+
573
+             $messagedatepl = date("Y-m-d H:i:s");
574
+
575
+             if ($ismms == 0) {
576
+
577
+                 $client = new RestClient($smsapikey, $smsapisecret);
578
+                 $response = $client->messages->create($fromsender,[$tonumber],$sentsmstext,["url" => $smsapideliveryrecurl]);
579
+                 $messagetextpl = $sentsmstext;
580
+	         $messageidinit = $response->getmessageUuid(0);
581
+                 $messageid = $messageidinit[0];
582
+
583
+                 if (property_exists($response, 'error')) { 
584
+                     $messagestatus = "Error: " . $response->error;
585
+                 } else { $messagestatus = 'The message has been accepted for delivery.'; }
586
+
587
+             } else {
588
+
589
+                 $mediaURLarr = [];
590
+                 $includedMediaFiles = '';
591
+
592
+                 for ($p = 0; $p < count($mmsfiles); $p++ ) {
593
+
594
+                      $userroot = $this->view->getRoot();
595
+                      $filetoshare = $userroot . "/SMS_Relentless/temp_files/".$mmsfiles[$p]."";
596
+
597
+                      $flsharetarget = $this->folder->newFile($filetoshare);
598
+
599
+	              $share = $this->shareManager->newShare();
600
+	              $share->setNode($flsharetarget);
601
+	              $share->setPermissions(Constants::PERMISSION_READ);
602
+	              $share->setShareType(\OC\Share\Constants::SHARE_TYPE_LINK);
603
+	              $share->setSharedBy($this->userId);
604
+                      $expirydate = DateTime::createFromFormat('Y-m-d H:i:s', $messagedatepl);
605
+                      $expirydate->add(new \DateInterval('P1D'));
606
+                      $share->setExpirationDate($expirydate);
607
+                      $shared = $this->shareManager->createShare($share);
608
+                      $shareToken = $shared->getToken();
609
+
610
+                      $hostnm = $_SERVER['REQUEST_SCHEME'] . "://" . $_SERVER['HTTP_HOST'];
611
+
612
+                      $mediaURLarr[] = $hostnm . "/s/" . $shareToken . "/download/" . $mmsfiles[$p];
613
+
614
+                      $includedMediaFiles .= "<div id='mmsTblUrl-" . mt_rand(1, 10000) . "' class='mmstblUrls' title='Download this file only if you trust the sender and the domain of the URL.'>" . $hostnm . "/s/" . $shareToken . "/download/" . $mmsfiles[$p] . "</div><br><br>";
615
+                 }
616
+
617
+		 $datatosendpl = ["src" => $fromsender, "dst" => $tonumber, "text" => $sentsmstext, "url" => $smsapideliveryrecurl, "type" => "mms", "media_urls" => $mediaURLarr];
618
+		 $postedparamspl = json_encode($datatosendpl);
619
+
620
+		 $chpl = curl_init();
621
+		 curl_setopt($chpl, CURLOPT_URL, 'https://'.$smsapikey.':'.$smsapisecret.'@api.plivo.com/v1/Account/'.$smsapikey.'/Message/');
622
+		 curl_setopt($chpl, CURLOPT_HTTPHEADER, array("Content-Type: application/json"));
623
+		 curl_setopt($chpl, CURLOPT_TIMEOUT, 300);
624
+		 curl_setopt($chpl, CURLOPT_RETURNTRANSFER, 1);
625
+		 curl_setopt($chpl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
626
+		 curl_setopt($chpl, CURLOPT_POST, 1);
627
+		 curl_setopt($chpl, CURLOPT_POSTFIELDS, $postedparamspl);
628
+		 $resultpl = curl_exec ($chpl);
629
+		 $statusCodepl = curl_getinfo($chpl, CURLINFO_HTTP_CODE);
630
+		 curl_close ($chpl);
631
+
632
+		 $decresultpl = json_decode($resultpl);
633
+
634
+                 if ($decresultpl) {
635
+                     if (property_exists($decresultpl, 'message_uuid')) {
636
+                         $messageidinit = $decresultpl->message_uuid;
637
+                         $messageid = $messageidinit[0];
638
+                     } else { $messageid = 'n/a'; }
639
+                 } else { $messageid = 'n/a'; }
640
+
641
+	         if (in_array($statusCodepl, [200, 201, 202, 203, 204, 205, 206])) {
642
+
643
+                     if (property_exists($decresultpl, 'error')) {
644
+                         $messagestatus = "Error: " . $decresultpl->error;
645
+                     } else { $messagestatus = 'The message has been accepted for delivery.'; }
646
+
647
+                 } else { $messagestatus = 'An error occurred while trying to send the message.'; }
648
+
649
+                 $messagetextpl = $sentsmstext . "<br><br><br>--- File(s) included in MMS ---<br><br>" . $includedMediaFiles;
650
+             }
651
+
652
+             if (preg_match('/[A-Za-z]+/', $fromsender)) {
653
+                 $messagefrom = "Plivo: " . $fromsender;
654
+             } else { $messagefrom = "Plivo: +" . $fromsender; }
655
+
656
+             $messageto = $tonumber;
657
+             $messagenetwork = '';
658
+             $messageprice = '';
659
+
660
+             $messagedelivery = '';
661
+
662
+             $sentmessagearr = [$messageid, $messagedatepl, $messagefrom, $messageto, $messagenetwork, $messageprice, $messagestatus, $messagedelivery, $messagetextpl];
663
+
664
+             $this->service->insertsentsms($this->userId, $displayname, $sentmessagearr);
665
+         }
666
+         return $displayname;
667
+    }
668
+
669
+
670
+    /**
671
+     * @NoAdminRequired
672
+     */
673
+    public function sendsmstwil($userId, $receiversPhoneNbs, $fromsender, $waitinterval, $sentsmstext, $ismms, $mmsfiles) {
674
+
675
+         $twsmsapicred = $this->service->getapicredentials($this->userId);
676
+
677
+         $sid = $twsmsapicred[15];
678
+         $token = $twsmsapicred[16];
679
+         $smsapirecurltw = $twsmsapicred[18];
680
+         $addDisplName = $twsmsapicred[24];
681
+
682
+         // Get the Display Name of the current user
683
+         $crtuser = $this->userManager->get($this->userId);
684
+         $displayname = $crtuser->getDisplayName();
685
+
686
+         if ($addDisplName == 1) {
687
+             $sentsmstext = $displayname . ": " . $sentsmstext;
688
+         }
689
+
690
+         $microinterval = $waitinterval * 1000;
691
+
692
+         foreach ($receiversPhoneNbs as $keytwil => $tonumbertw) {
693
+
694
+             usleep($microinterval);
695
+
696
+             $messagedatetw = date("Y-m-d H:i:s");
697
+
698
+             if ($ismms == 0) {
699
+
700
+                 $datatoposttw = [["To" => $tonumbertw, "From" => $fromsender, "Body" => $sentsmstext, "StatusCallback" => $smsapirecurltw]];
701
+                 $sentsmstextfintw = $sentsmstext;
702
+
703
+             } else {
704
+
705
+                 $mediaURLs = [];
706
+                 $includedMediaFiles = '';
707
+
708
+                 for ($p = 0; $p < count($mmsfiles); $p++ ) {
709
+
710
+                      $userroot = $this->view->getRoot();
711
+                      $filetoshare = $userroot . "/SMS_Relentless/temp_files/".$mmsfiles[$p]."";
712
+
713
+                      $flsharetarget = $this->folder->newFile($filetoshare);
714
+
715
+	              $share = $this->shareManager->newShare();
716
+	              $share->setNode($flsharetarget);
717
+	              $share->setPermissions(Constants::PERMISSION_READ);
718
+	              $share->setShareType(\OC\Share\Constants::SHARE_TYPE_LINK);
719
+	              $share->setSharedBy($this->userId);
720
+                      $expirydate = DateTime::createFromFormat('Y-m-d H:i:s', $messagedatetw);
721
+                      $expirydate->add(new \DateInterval('P1D'));
722
+                      $share->setExpirationDate($expirydate);
723
+                      $shared = $this->shareManager->createShare($share);
724
+                      $shareToken = $shared->getToken();
725
+
726
+                      $hostnm = $_SERVER['REQUEST_SCHEME'] . "://" . $_SERVER['HTTP_HOST'];
727
+
728
+                      $mediaURLs[] = $hostnm . "/s/" . $shareToken . "/download/" . $mmsfiles[$p];
729
+
730
+                      $includedMediaFiles .= "<div id='mmsTblUrl-" . mt_rand(1, 10000) . "' class='mmstblUrls' title='Download this file only if you trust the sender and the domain of the URL.'>" . $hostnm . "/s/" . $shareToken . "/download/" . $mmsfiles[$p] . "</div><br><br>";
731
+                 }
732
+
733
+                 $datatoposttw = [["To" => $tonumbertw, "From" => $fromsender, "Body" => $sentsmstext, "StatusCallback" => $smsapirecurltw]];
734
+
735
+                 for ($m = 0; $m < count($mediaURLs); $m++) {
736
+                      array_push($datatoposttw, ["MediaUrl" => $mediaURLs[$m]]);
737
+                 }
738
+
739
+                 $sentsmstextfintw = $sentsmstext . "<br><br><br>--- File(s) included in MMS ---<br><br>" . $includedMediaFiles;
740
+             }
741
+
742
+             $postedsendingfl = implode('&', array_map('http_build_query', $datatoposttw));
743
+
744
+	     $chtw = curl_init();
745
+	     curl_setopt($chtw, CURLOPT_URL, 'https://api.twilio.com/2010-04-01/Accounts/'.$sid.'/Messages.json');
746
+	     curl_setopt($chtw, CURLOPT_TIMEOUT, 300);
747
+	     curl_setopt($chtw, CURLOPT_RETURNTRANSFER, 1);
748
+	     curl_setopt($chtw, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
749
+             curl_setopt($chtw, CURLOPT_USERPWD, "$sid:$token");
750
+	     curl_setopt($chtw, CURLOPT_POST, 1);
751
+             curl_setopt($chtw, CURLOPT_POSTFIELDS, $postedsendingfl);
752
+
753
+	     $resulttw = curl_exec ($chtw);
754
+	     $statusCodetw = curl_getinfo($chtw, CURLINFO_HTTP_CODE);
755
+	     curl_close ($chtw);
756
+
757
+             $decresulttw = json_decode($resulttw);
758
+
759
+             if ($decresulttw) {
760
+                 if (property_exists($decresulttw, 'sid')) { $messageidtw = $decresulttw->sid; } else { $messageidtw = 'n/a'; }
761
+             } else { $messageidtw = 'n/a'; }
762
+
763
+	     if (in_array($statusCodetw, [200, 201, 202, 203, 204, 205, 206])) {
764
+                 $messagestatustw = 'The message has been accepted for delivery.';
765
+             } else {
766
+                 $messagestatustw = 'An error occurred while trying to send the message.';
767
+             }
768
+
769
+             if (preg_match('/[A-Za-z]+/', $fromsender)) {
770
+                 $messagefromtw = "Twilio: " . $fromsender;
771
+             } else { $messagefromtw = "Twilio: " . $fromsender; }
772
+
773
+             $messagenetworktw = '';
774
+             $messagepricetw = '';
775
+             $messagedeliverytw = '';
776
+
777
+             $sentmessagearr = [$messageidtw, $messagedatetw, $messagefromtw, $tonumbertw, $messagenetworktw, $messagepricetw, $messagestatustw, $messagedeliverytw, $sentsmstextfintw];
778
+
779
+             $this->service->insertsentsms($this->userId, $displayname, $sentmessagearr);
780
+         }
781
+         return $displayname;
782
+    }
783
+
784
+
785
+    /**
786
+     * @NoAdminRequired
787
+     */
788
+    public function sendsmsflow($userId, $receiversPhoneNbs, $fromsender, $waitinterval, $sentsmstext, $ismms, $mmsfiles) {
789
+
790
+         $flsmsapicred = $this->service->getapicredentials($this->userId);
791
+
792
+         $flowapikey = $flsmsapicred[20];
793
+         $flowapisecret = $flsmsapicred[21];
794
+         $flowdelrecurl = $flsmsapicred[23];
795
+         $addDisplName = $flsmsapicred[24];
796
+
797
+         // Get the Display Name of the current user
798
+         $crtuser = $this->userManager->get($this->userId);
799
+         $displayname = $crtuser->getDisplayName();
800
+
801
+         if ($addDisplName == 1) {
802
+             $sentsmstext = $displayname . ": " . $sentsmstext;
803
+         }
804
+
805
+         $sentsmstextproc = str_replace('"','\\"', $sentsmstext);
806
+
807
+         $microinterval = $waitinterval * 1000;
808
+
809
+         foreach ($receiversPhoneNbs as $keyflow => $tonumberfl) {
810
+
811
+             usleep($microinterval);
812
+
813
+             $messagedatefl = date("Y-m-d H:i:s");
814
+
815
+             if ($ismms == 0) {
816
+
817
+                 $messagetextfinfl = $sentsmstext;
818
+                 $postedparamsfl = json_encode(["to" => $tonumberfl, "from" => $fromsender, "body" => $sentsmstextproc, "dlr_callback" => $flowdelrecurl]);
819
+
820
+             } else {
821
+
822
+		 $mediaurlsarr = [];
823
+		 $includedMediaFiles = '';
824
+
825
+		 for ($p = 0; $p < count($mmsfiles); $p++ ) {
826
+
827
+		      $userroot = $this->view->getRoot();
828
+		      $filetoshare = $userroot . "/SMS_Relentless/temp_files/".$mmsfiles[$p]."";
829
+
830
+		      $flsharetarget = $this->folder->newFile($filetoshare);
831
+
832
+		      $share = $this->shareManager->newShare();
833
+		      $share->setNode($flsharetarget);
834
+		      $share->setPermissions(Constants::PERMISSION_READ);
835
+		      $share->setShareType(\OC\Share\Constants::SHARE_TYPE_LINK);
836
+		      $share->setSharedBy($this->userId);
837
+                      $expirydate = DateTime::createFromFormat('Y-m-d H:i:s', $messagedatefl);
838
+                      $expirydate->add(new \DateInterval('P1D'));
839
+                      $share->setExpirationDate($expirydate);
840
+		      $shared = $this->shareManager->createShare($share);
841
+		      $shareToken = $shared->getToken();
842
+
843
+                      $hostnm = $_SERVER['REQUEST_SCHEME'] . "://" . $_SERVER['HTTP_HOST'];
844
+
845
+		      $mediaurlsarr[] = $hostnm . "/s/" . $shareToken . "/download/" . $mmsfiles[$p];
846
+
847
+                      $includedMediaFiles .= "<div id='mmsTblUrl-" . mt_rand(1, 10000) . "' class='mmstblUrls' title='Download this file only if you trust the sender and the domain of the URL.'>" . $hostnm . "/s/" . $shareToken . "/download/" . $mmsfiles[$p] . "</div><br><br>";
848
+		 }
849
+
850
+                 $messagetextfinfl = $sentsmstext . "<br><br><br>--- File(s) included in MMS ---<br><br>" . $includedMediaFiles;
851
+
852
+                 $postedparamsfl = json_encode(["to" => $tonumberfl, "from" => $fromsender, "body" => $sentsmstextproc, "dlr_callback" => $flowdelrecurl, "media_urls" => $mediaurlsarr]);
853
+             }
854
+
855
+	     $chfl = curl_init();
856
+	     curl_setopt($chfl, CURLOPT_URL, 'https://'.$flowapikey.':'.$flowapisecret.'@api.flowroute.com/v2.1/messages');
857
+	     curl_setopt($chfl, CURLOPT_HTTPHEADER, array("Content-Type: application/vnd.api+json"));
858
+	     curl_setopt($chfl, CURLOPT_TIMEOUT, 300);
859
+	     curl_setopt($chfl, CURLOPT_RETURNTRANSFER, 1);
860
+	     curl_setopt($chfl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
861
+	     curl_setopt($chfl, CURLOPT_POST, 1);
862
+             curl_setopt($chfl, CURLOPT_POSTFIELDS, $postedparamsfl);
863
+	     $resultfl = curl_exec ($chfl);
864
+	     $statusCode = curl_getinfo($chfl, CURLINFO_HTTP_CODE);
865
+	     curl_close ($chfl);
866
+
867
+             $decresultfl = json_decode($resultfl);
868
+
869
+             if ($decresultfl) {
870
+                 if (property_exists($decresultfl, 'data')) { 
871
+                     $messageidfl = $decresultfl->data->id;
872
+                 } else { $messageidfl = 'n/a'; }
873
+             } else { $messageidfl = 'n/a'; }
874
+
875
+	     if (in_array($statusCode, [200, 201, 202, 203, 204, 205, 206])) {
876
+                 $messagestatusfl = 'The message has been accepted for delivery.'; 
877
+             } else { 
878
+                 $messagestatusfl = 'An error occurred while trying to send the message.'; 
879
+             }
880
+
881
+             if (preg_match('/[A-Za-z]+/', $fromsender)) {
882
+                 $messagefromfl = "Flowroute: " . $fromsender;
883
+             } else { $messagefromfl = "Flowroute: " . $fromsender; }
884
+
885
+             $messagetofl = $tonumberfl;
886
+             $messagenetworkfl = '';
887
+             $messagepricefl = '';
888
+             $messagedeliveryfl = '';
889
+
890
+             $sentmessagearr = [$messageidfl, $messagedatefl, $messagefromfl, $messagetofl, $messagenetworkfl, $messagepricefl, $messagestatusfl, $messagedeliveryfl, $messagetextfinfl];
891
+
892
+             $this->service->insertsentsms($this->userId, $displayname, $sentmessagearr);
893
+         }
894
+         return $displayname;
895
+    }
896
+
897
+
898
+    /**
899
+     * @NoAdminRequired
900
+     */
901
+    public function saveoldrecrows($userId, $oldrecRows) {
902
+
903
+           // Create the folder for removed messages if it doesn't exist
904
+           if ($this->folder->nodeExists('SMS_Relentless/removed_received_messages') == false) {
905
+               $this->folder->newFolder('SMS_Relentless/removed_received_messages');
906
+           }
907
+           $savecheck = 0;
908
+
909
+           if (count($oldrecRows) > 1) {
910
+               $msfileContent = implode("", $oldrecRows);
911
+
912
+               $delrowsdate = date("Y-m-d_H-i-s");
913
+               $msfileName = "Received_Messages_Deleted_On_" . $delrowsdate . ".csv";
914
+
915
+               $userroot = $this->view->getRoot();
916
+               $targetfile = $userroot . "/SMS_Relentless/removed_received_messages/" . $msfileName;
917
+
918
+               $target = $this->folder->newFile($targetfile);
919
+               $target->putContent($msfileContent);
920
+
921
+               if ($this->filesystem->file_get_contents($targetfile) != '') {
922
+                   $savecheck = 1;
923
+               }
924
+           }
925
+
926
+           return $savecheck;
927
+    }
928
+
929
+
930
+    /**
931
+     * @NoAdminRequired
932
+     */
933
+    public function saveoldsentrows($userId, $oldsentRows) {
934
+
935
+           // Create the folder for removed messages if it doesn't exist
936
+           if ($this->folder->nodeExists('SMS_Relentless/removed_sent_messages') == false) {
937
+               $this->folder->newFolder('SMS_Relentless/removed_sent_messages');
938
+           }
939
+           $savesentcheck = 0;
940
+
941
+           if (count($oldsentRows) > 1) {
942
+               $sntfileContent = implode("", $oldsentRows);
943
+
944
+               $delsentrowsdate = date("Y-m-d_H-i-s");
945
+               $sntfileName = "Sent_Messages_Deleted_On_" . $delsentrowsdate . ".csv";
946
+
947
+               $userroot = $this->view->getRoot();
948
+               $snttargetfile = $userroot . "/SMS_Relentless/removed_sent_messages/" . $sntfileName;
949
+
950
+               $snttarget = $this->folder->newFile($snttargetfile);
951
+               $snttarget->putContent($sntfileContent);
952
+
953
+               if ($this->filesystem->file_get_contents($snttargetfile) != '') {
954
+                   $savesentcheck = 1;
955
+               }
956
+           }
957
+
958
+           return $savesentcheck;
959
+    }
960
+
961
+
962
+    /**
963
+     * @NoAdminRequired
964
+     */
965
+    public function getreceivedtable($userId) {
966
+           return $this->service->getreceivedtable($this->userId);
967
+    }
968
+
969
+    /**
970
+     * @NoAdminRequired
971
+     */
972
+    public function getreceivedtablefordel($userId) {
973
+           return $this->service->getreceivedtablefordel($this->userId);
974
+    }
975
+
976
+    /**
977
+     * @NoAdminRequired
978
+     */
979
+    public function removerecrows($userId, $recmessagedbIDs) {
980
+           return $this->service->removerecrows($this->userId, $recmessagedbIDs);
981
+    }
982
+
983
+    /**
984
+     * @NoAdminRequired
985
+     */
986
+    public function getsenttable($userId) {
987
+           return $this->service->getsenttable($this->userId);
988
+    }
989
+
990
+    /**
991
+     * @NoAdminRequired
992
+     */
993
+    public function getsenttablefordel($userId) {
994
+           return $this->service->getsenttablefordel($this->userId);
995
+    }
996
+
997
+    /**
998
+     * @NoAdminRequired
999
+     */
1000
+    public function removesentrows($userId, $sentmessagedbIDs) {
1001
+           return $this->service->removesentrows($this->userId, $sentmessagedbIDs);
1002
+    }
1003
+
1004
+    /**
1005
+     * @NoAdminRequired
1006
+     */
1007
+    public function getgroupedtable($userId) {
1008
+           return $this->service->getgroupedtable($this->userId);
1009
+    }
1010
+
1011
+    /**
1012
+     * @NoAdminRequired
1013
+     */
1014
+    public function savedisplayname($userId, $authorDisplayname, $from) {
1015
+           return $this->service->savedisplayname($this->userId, $authorDisplayname, $from);
1016
+    }
1017
+
1018
+    /**
1019
+     * @NoAdminRequired
1020
+     */
1021
+    public function getmsgsperpagenewmsg($userId) {
1022
+           return $this->service->getmsgsperpagenewmsg($this->userId);
1023
+    }
1024
+
1025
+    /**
1026
+     * @NoAdminRequired
1027
+     */
1028
+    public function getnewmsgindicator($userId) {
1029
+           return $this->service->getnewmsgindicator($this->userId);
1030
+    }
1031
+
1032
+    /**
1033
+     * @NoAdminRequired
1034
+     */
1035
+    public function getdelrecsettings($userId) {
1036
+           return $this->service->getdelrecsettings($this->userId);
1037
+    }
1038
+
1039
+    public function updatenumberrestrictions($userId, $savedByDsplname, $phoneNumber, $groups, $users) {
1040
+           return $this->service->updatenumberrestrictions($this->userId, $savedByDsplname, $phoneNumber, $groups, $users);
1041
+    }
1042
+
1043
+    public function updatekeysallowedusers($userId, $groups, $users, $provider) {
1044
+           return $this->service->updatekeysallowedusers($this->userId, $groups, $users, $provider);
1045
+    }
1046
+
1047
+    public function removenumberrestrictions($userId, $phoneNumber) {
1048
+           return $this->service->removenumberrestrictions($this->userId, $phoneNumber);
1049
+    }
1050
+
1051
+    /**
1052
+     * @NoAdminRequired
1053
+     */
1054
+    public function updateautoreplies($userId, $savedByDsplname, $phoneNumber, $daysOfWeek, $dailyStart, $dailyEnd, $vacationStart, $vacationEnd, $messageText) {
1055
+           return $this->service->updateautoreplies($this->userId, $savedByDsplname, $phoneNumber, $daysOfWeek, $dailyStart, $dailyEnd, $vacationStart, $vacationEnd, $messageText);
1056
+    }
1057
+
1058
+    /**
1059
+     * @NoAdminRequired
1060
+     */
1061
+    public function removeautoreplies($userId, $phoneNumber) {
1062
+           return $this->service->removeautoreplies($this->userId, $phoneNumber);
1063
+    }
1064
+
1065
+    /**
1066
+     * @NoAdminRequired
1067
+     */
1068
+    public function getsettings($userId) {
1069
+           return $this->service->getsettings($this->userId);
1070
+    }
1071
+
1072
+    public function getadminsettings($userId) {
1073
+           return $this->service->getadminsettings($this->userId);
1074
+    }
1075
+
1076
+    /**
1077
+     * @NoAdminRequired
1078
+     */
1079
+    public function getautoreplyconf($userId) {
1080
+
1081
+           // Get the available phone numbers for the current user (the restricted phone numbers are excluded)
1082
+           $availphonenmbrs = $this->getsmsnumbers($this->userId);
1083
+
1084
+           // Get the display name of the current user
1085
+           $usrid = $this->userId;
1086
+           $getusrdnm = $this->connection->prepare('SELECT `uid`, `name`, `value` FROM `*PREFIX*accounts_data` WHERE `uid` = ? AND `name` = ?');
1087
+	   $getusrdnmres = $getusrdnm->execute([$usrid, 'displayname']);
1088
+	   $getusrdnmdata = $getusrdnmres->fetch();
1089
+	   $userDisplayNm = $getusrdnmdata['value'];
1090
+	   $getusrdnmres->closeCursor();
1091
+
1092
+           // Get the auto-replies for the available phone numbers
1093
+           $getautorpl = $this->connection->prepare('SELECT `saved_by_dsplname`, `phone_number`, `days_of_week`, `daily_start`, `daily_end`, `vacation_start`, `vacation_end`, 
1094
+                                                    `message_text` FROM `*PREFIX*sms_relent_autorply`');
1095
+	   $getautorplres = $getautorpl->execute();
1096
+           $autorplconf = [];
1097
+	   while ($acdatausrdnadm = $getautorplres->fetch()) {
1098
+                  $autorplconf[] = $acdatausrdnadm;
1099
+           }
1100
+	   $getautorplres->closeCursor();
1101
+
1102
+           if ($autorplconf) {
1103
+
1104
+               $autoreplyconf = [];
1105
+               foreach ($autorplconf as $arkey => $arvalue) {
1106
+                        if (in_array($arvalue['phone_number'], $availphonenmbrs)) {
1107
+                            $autoreplyconf[] = $arvalue;
1108
+                        }
1109
+               }
1110
+
1111
+           } else { $autoreplyconf = ''; }
1112
+
1113
+           $autoreplyfdb = ['userdisplayname' => $userDisplayNm, 'phonenumbers' => $availphonenmbrs, 'autoreplies' => $autoreplyconf];
1114
+
1115
+           return $autoreplyfdb;
1116
+    }
1117
+
1118
+    /**
1119
+     * @NoAdminRequired
1120
+     */
1121
+    public function getgroupedpernumber($userId, $phoneNumber) {
1122
+           return $this->service->getgroupedpernumber($this->userId, $phoneNumber);
1123
+    }
1124
+
1125
+    /**
1126
+     * @NoAdminRequired
1127
+     */
1128
+    public function getgroupedforreply($userId, $phoneNmbrFrom, $phoneNmbrTo) {
1129
+           return $this->service->getgroupedforreply($this->userId, $phoneNmbrFrom, $phoneNmbrTo);
1130
+    }
1131
+
1132
+    /**
1133
+     * @NoAdminRequired
1134
+     */
1135
+    public function updatesettings($userId, $telapiUrlRec, $telapiUrl, $nexapiUrlRec, $nexapiUrl, $twilapiUrlRec, $twilapiUrl, $flowapiUrlRec, $flowapiUrl, $messagesperpage, $getNotify, $notificationEmail, $getsmsinemail, $showDisplayNames, $addDisplayNames, $msgCheckInterval) {
1136
+           return $this->service->updatesettings($this->userId, $telapiUrlRec, $telapiUrl, $nexapiUrlRec, $nexapiUrl, $twilapiUrlRec, $twilapiUrl, $flowapiUrlRec, $flowapiUrl, $messagesperpage, $getNotify, $notificationEmail, $getsmsinemail, $showDisplayNames, $addDisplayNames, $msgCheckInterval);
1137
+    }
1138
+
1139
+    public function updateadminsettings($userId, $telapiKey, $telPubKey, $telapiUrlRec, $telapiUrl, $messagingProfileId, $nexapiKey, $nexapiSecret, $nexapiUrlRec, $nexapiUrl, $telSenderName, $nexSenderName, $twilapiKey, $twilapiSecret, $twilapiUrlRec, $twilapiUrl, $twilSenderName, $flowapiKey, $flowapiSecret, $flowapiUrlRec, $flowapiUrl, $showAllMessages) {
1140
+           return $this->service->updateadminsettings($this->userId, $telapiKey, $telPubKey, $telapiUrlRec, $telapiUrl, $messagingProfileId, $nexapiKey, $nexapiSecret, $nexapiUrlRec, $nexapiUrl, $telSenderName, $nexSenderName, $twilapiKey, $twilapiSecret, $twilapiUrlRec, $twilapiUrl, $twilSenderName, $flowapiKey, $flowapiSecret, $flowapiUrlRec, $flowapiUrl, $showAllMessages);
1141
+    }
1142
+
1143
+    public function updatepersadmnsettings($userId, $messagesperpage, $getNotify, $notificationEmail, $getsmsinemail, $showDisplayNames, $addDisplayNames, $msgCheckInterval) {
1144
+           return $this->service->updatepersadmnsettings($this->userId, $messagesperpage, $getNotify, $notificationEmail, $getsmsinemail, $showDisplayNames, $addDisplayNames, $msgCheckInterval);
1145
+    }
1146
+}
0 1147
new file mode 100644
... ...
@@ -0,0 +1,461 @@
1
+<?php
2
+/**
3
+ * @copyright 2021 Double Bastion LLC <www.doublebastion.com>
4
+ *
5
+ * @author Double Bastion LLC
6
+ *
7
+ * @license GNU AGPL version 3 or any later version
8
+ *
9
+ * This program is free software; you can redistribute it and/or
10
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
11
+ * License as published by the Free Software Foundation; either
12
+ * version 3 of the License, or any later version.
13
+ *
14
+ * This program is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
18
+ *
19
+ * You should have received a copy of the GNU Affero General Public
20
+ * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
+ *
22
+ */
23
+
24
+declare(strict_types=1);
25
+
26
+namespace OCA\SMSRelentless\Migration;
27
+
28
+use Closure;
29
+use OCP\DB\Types;
30
+use OCP\DB\ISchemaWrapper;
31
+use OCP\IDBConnection;
32
+use OCP\Migration\IOutput;
33
+use OCP\Migration\SimpleMigrationStep;
34
+
35
+
36
+class Version133Date20240215094712 extends SimpleMigrationStep {
37
+
38
+        /** @var IDBConnection */
39
+        private $connection;
40
+
41
+        /**
42
+         * @param IDBConnection $connection
43
+         */
44
+        public function __construct(IDBConnection $connection) {
45
+                $this->connection = $connection;
46
+        }
47
+
48
+	/**
49
+	 * @param IOutput $output
50
+	 * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
51
+	 * @param array $options
52
+	 * @return null|ISchemaWrapper
53
+	 */
54
+	public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper {
55
+		/** @var ISchemaWrapper $schema */
56
+		$schema = $schemaClosure();
57
+
58
+		if (!$schema->hasTable('sms_relent_settings')) {
59
+			$table = $schema->createTable('sms_relent_settings');
60
+			$table->addColumn('id', Types::BIGINT, [
61
+				'autoincrement' => true,
62
+				'notnull' => true,
63
+                                'length' => 11,
64
+                                'unsigned' => true,
65
+			]);
66
+			$table->addColumn('user_id', Types::STRING, [
67
+				'notnull' => true,
68
+				'length' => 128,
69
+			]);
70
+			$table->addColumn('telapi_key', Types::STRING, [
71
+				'notnull' => true,
72
+				'length' => 512,
73
+			]);
74
+			$table->addColumn('tel_pub_key', Types::STRING, [
75
+				'notnull' => true,
76
+				'length' => 512,
77
+			]);
78
+			$table->addColumn('telapi_url_rec', Types::STRING, [
79
+				'notnull' => true,
80
+				'length' => 512,
81
+			]);
82
+			$table->addColumn('telapi_url', Types::STRING, [
83
+				'notnull' => true,
84
+				'length' => 512,
85
+			]);
86
+			$table->addColumn('messaging_profile_id', Types::STRING, [
87
+				'notnull' => true,
88
+				'length' => 512,
89
+			]);
90
+			$table->addColumn('nexapi_key', Types::STRING, [
91
+				'notnull' => true,
92
+				'length' => 512,
93
+			]);
94
+			$table->addColumn('nexapi_secret', Types::STRING, [
95
+				'notnull' => true,
96
+				'length' => 512,
97
+			]);
98
+			$table->addColumn('nexapi_url_rec', Types::STRING, [
99
+				'notnull' => true,
100
+				'length' => 512,
101
+			]);
102
+			$table->addColumn('nexapi_url', Types::STRING, [
103
+				'notnull' => true,
104
+				'length' => 512,
105
+			]);
106
+			$table->addColumn('twilapi_key', Types::STRING, [
107
+				'notnull' => true,
108
+				'length' => 512,
109
+			]);
110
+			$table->addColumn('twilapi_secret', Types::STRING, [
111
+				'notnull' => true,
112
+				'length' => 512,
113
+			]);
114
+			$table->addColumn('twilapi_url_rec', Types::STRING, [
115
+				'notnull' => true,
116
+				'length' => 512,
117
+			]);
118
+			$table->addColumn('twilapi_url', Types::STRING, [
119
+				'notnull' => true,
120
+				'length' => 512,
121
+			]);
122
+			$table->addColumn('flowapi_key', Types::STRING, [
123
+				'notnull' => true,
124
+				'length' => 512,
125
+			]);
126
+			$table->addColumn('flowapi_secret', Types::STRING, [
127
+				'notnull' => true,
128
+				'length' => 512,
129
+			]);
130
+			$table->addColumn('flowapi_url_rec', Types::STRING, [
131
+				'notnull' => true,
132
+				'length' => 512,
133
+			]);
134
+			$table->addColumn('flowapi_url', Types::STRING, [
135
+				'notnull' => true,
136
+				'length' => 512,
137
+			]);
138
+			$table->addColumn('tel_sender_name', Types::STRING, [
139
+				'notnull' => false,
140
+				'length' => 48,
141
+				'default' => '',
142
+			]);
143
+			$table->addColumn('nex_sender_name', Types::STRING, [
144
+				'notnull' => false,
145
+				'length' => 48,
146
+				'default' => '',
147
+			]);
148
+			$table->addColumn('twil_sender_name', Types::STRING, [
149
+				'notnull' => false,
150
+				'length' => 48,
151
+				'default' => '',
152
+			]);
153
+			$table->addColumn('flow_sender_name', Types::STRING, [
154
+				'notnull' => false,
155
+				'length' => 48,
156
+				'default' => '',
157
+			]);
158
+			$table->addColumn('messagesperpage', Types::INTEGER, [
159
+				'notnull' => false,
160
+				'length' => 10,
161
+                                'unsigned' => true,
162
+			]);
163
+			$table->addColumn('get_notify', Types::SMALLINT, [
164
+				'notnull' => false,
165
+				'length' => 1,
166
+			]);
167
+			$table->addColumn('notification_email', Types::STRING, [
168
+				'notnull' => false,
169
+				'length' => 512,
170
+				'default' => '',
171
+			]);
172
+			$table->addColumn('getsmsinemail', Types::SMALLINT, [
173
+				'notnull' => false,
174
+				'length' => 1,
175
+			]);
176
+			$table->addColumn('show_all_messages', Types::SMALLINT, [
177
+				'notnull' => false,
178
+				'length' => 1,
179
+			]);
180
+			$table->addColumn('show_display_names', Types::SMALLINT, [
181
+				'notnull' => false,
182
+				'length' => 1,
183
+			]);
184
+			$table->addColumn('add_display_names', Types::SMALLINT, [
185
+				'notnull' => false,
186
+				'length' => 1,
187
+			]);
188
+			$table->addColumn('available_numbers', Types::TEXT, [
189
+				'notnull' => false,
190
+                                'default' => '',
191
+			]);
192
+			$table->addColumn('msg_check_interval', Types::INTEGER, [
193
+				'notnull' => false,
194
+				'length' => 10,
195
+                                'unsigned' => true,
196
+			]);
197
+			$table->addColumn('new_message_rcd', Types::SMALLINT, [
198
+				'notnull' => false,
199
+				'length' => 1,
200
+			]);
201
+                        $table->setPrimaryKey(['id']);
202
+                        $table->addUniqueIndex(['id']);
203
+
204
+		} else {
205
+
206
+                        $table = $schema->getTable('sms_relent_settings');
207
+
208
+			$table->addColumn('available_numbers', Types::TEXT, [
209
+				'notnull' => false,
210
+                                'default' => '',
211
+			]);
212
+			$table->addColumn('msg_check_interval', Types::INTEGER, [
213
+				'notnull' => false,
214
+				'length' => 10,
215
+                                'unsigned' => true,
216
+			]);
217
+			$table->addColumn('new_message_rcd', Types::SMALLINT, [
218
+				'notnull' => false,
219
+				'length' => 1,
220
+			]);
221
+                }
222
+
223
+
224
+		if (!$schema->hasTable('sms_relent_received')) {
225
+			$table = $schema->createTable('sms_relent_received');
226
+			$table->addColumn('id', Types::BIGINT, [
227
+				'autoincrement' => true,
228
+				'notnull' => true,
229
+                                'length' => 11,
230
+                                'unsigned' => true,
231
+			]);
232
+			$table->addColumn('user_id', Types::STRING, [
233
+				'notnull' => true,
234
+				'length' => 64,
235
+			]);
236
+			$table->addColumn('message_id', Types::STRING, [
237
+				'notnull' => true,
238
+				'length' => 512,
239
+			]);
240
+			$table->addColumn('date', Types::DATETIME, [
241
+				'notnull' => true,
242
+			]);
243
+			$table->addColumn('from', Types::STRING, [
244
+				'notnull' => true,
245
+				'length' => 128,
246
+			]);
247
+			$table->addColumn('to', Types::STRING, [
248
+				'notnull' => true,
249
+				'length' => 128,
250
+			]);
251
+			$table->addColumn('message', Types::TEXT, [
252
+				'notnull' => false,
253
+				'default' => '',
254
+			]);
255
+			$table->addColumn('author_displayname', Types::STRING, [
256
+				'notnull' => true,
257
+				'length' => 255,
258
+			]);
259
+			$table->addColumn('internal_sender', Types::SMALLINT, [
260
+				'notnull' => false,
261
+				'length' => 1,
262
+			]);
263
+                        $table->setPrimaryKey(['id']);
264
+                        $table->addUniqueIndex(['id']);
265
+		}
266
+
267
+
268
+		if (!$schema->hasTable('sms_relent_sent')) {
269
+			$table = $schema->createTable('sms_relent_sent');
270
+			$table->addColumn('id', Types::BIGINT, [
271
+				'autoincrement' => true,
272
+				'notnull' => true,
273
+                                'length' => 11,
274
+                                'unsigned' => true,
275
+			]);
276
+			$table->addColumn('user_id', Types::STRING, [
277
+				'notnull' => true,
278
+				'length' => 64,
279
+			]);
280
+			$table->addColumn('message_id', Types::STRING, [
281
+				'notnull' => true,
282
+				'length' => 512,
283
+			]);
284
+			$table->addColumn('date', Types::DATETIME, [
285
+				'notnull' => true,
286
+			]);
287
+			$table->addColumn('from', Types::STRING, [
288
+				'notnull' => true,
289
+				'length' => 128,
290
+			]);
291
+			$table->addColumn('to', Types::STRING, [
292
+				'notnull' => true,
293
+				'length' => 128,
294
+			]);
295
+			$table->addColumn('network ', Types::STRING, [
296
+				'notnull' => false,
297
+				'length' => 64,
298
+				'default' => '',
299
+			]);
300
+			$table->addColumn('price', Types::STRING, [
301
+				'notnull' => false,
302
+				'length' => 64,
303
+				'default' => '',
304
+			]);
305
+			$table->addColumn('status', Types::STRING, [
306
+				'notnull' => false,
307
+				'length' => 512,
308
+				'default' => '',
309
+			]);
310
+			$table->addColumn('deliveryreceipt', Types::STRING, [
311
+				'notnull' => false,
312
+				'length' => 64,
313
+				'default' => '',
314
+			]);
315
+			$table->addColumn('message', Types::TEXT, [
316
+				'notnull' => false,
317
+                                'default' => '',
318
+			]);
319
+			$table->addColumn('author_displayname', Types::STRING, [
320
+				'notnull' => true,
321
+				'length' => 255,
322
+			]);
323
+                        $table->setPrimaryKey(['id']);
324
+                        $table->addUniqueIndex(['id']);
325
+		}
326
+
327
+
328
+		if (!$schema->hasTable('sms_relent_autorply')) {
329
+			$table = $schema->createTable('sms_relent_autorply');
330
+			$table->addColumn('id', Types::BIGINT, [
331
+				'autoincrement' => true,
332
+				'notnull' => true,
333
+                                'length' => 11,
334
+                                'unsigned' => true,
335
+			]);
336
+			$table->addColumn('user_id', Types::STRING, [
337
+				'notnull' => true,
338
+				'length' => 128,
339
+			]);
340
+			$table->addColumn('saved_by_dsplname', Types::STRING, [
341
+				'notnull' => true,
342
+				'length' => 255,
343
+			]);
344
+			$table->addColumn('phone_number', Types::STRING, [
345
+				'notnull' => true,
346
+				'length' => 128,
347
+			]);
348
+			$table->addColumn('days_of_week', Types::STRING, [
349
+				'notnull' => false,
350
+				'length' => 64,
351
+                                'default' => '',
352
+			]);
353
+			$table->addColumn('daily_start', Types::STRING, [
354
+				'notnull' => false,
355
+				'length' => 8,
356
+                                'default' => '',
357
+			]);
358
+			$table->addColumn('daily_end', Types::STRING, [
359
+				'notnull' => false,
360
+				'length' => 8,
361
+                                'default' => '',
362
+			]);
363
+			$table->addColumn('vacation_start', Types::DATETIME, [
364
+				'notnull' => false,
365
+			]);
366
+			$table->addColumn('vacation_end', Types::DATETIME, [
367
+				'notnull' => false,
368
+			]);
369
+			$table->addColumn('message_text', Types::TEXT, [
370
+				'notnull' => false,
371
+                                'default' => '',
372
+			]);
373
+                        $table->setPrimaryKey(['id']);
374
+                        $table->addUniqueIndex(['id']);
375
+		}
376
+
377
+
378
+		if (!$schema->hasTable('sms_relent_restrict')) {
379
+			$table = $schema->createTable('sms_relent_restrict');
380
+			$table->addColumn('id', Types::BIGINT, [
381
+				'autoincrement' => true,
382
+				'notnull' => true,
383
+                                'length' => 11,
384
+                                'unsigned' => true,
385
+			]);
386
+			$table->addColumn('user_id', Types::STRING, [
387
+				'notnull' => true,
388
+				'length' => 128,
389
+			]);
390
+			$table->addColumn('saved_by_dsplname', Types::STRING, [
391
+				'notnull' => true,
392
+				'length' => 255,
393
+			]);
394
+			$table->addColumn('phone_number', Types::STRING, [
395
+				'notnull' => true,
396
+				'length' => 128,
397
+			]);
398
+			$table->addColumn('groups', Types::STRING, [
399
+				'notnull' => true,
400
+				'length' => 2048,
401
+			]);
402
+			$table->addColumn('users', Types::STRING, [
403
+				'notnull' => true,
404
+				'length' => 2048,
405
+			]);
406
+                        $table->setPrimaryKey(['id']);
407
+                        $table->addUniqueIndex(['id']);
408
+		}
409
+
410
+		if (!$schema->hasTable('sms_relent_subac')) {
411
+			$table = $schema->createTable('sms_relent_subac');
412
+			$table->addColumn('id', Types::BIGINT, [
413
+				'autoincrement' => true,
414
+				'notnull' => true,
415
+                                'length' => 11,
416
+                                'unsigned' => true,
417
+			]);
418
+			$table->addColumn('user_id', Types::STRING, [
419
+				'notnull' => true,
420
+				'length' => 128,
421
+			]);
422
+			$table->addColumn('tnx_groups_allowed', Types::TEXT, [
423
+				'notnull' => false,
424
+                                'default' => '',
425
+			]);
426
+			$table->addColumn('tnx_users_allowed', Types::TEXT, [
427
+				'notnull' => false,
428
+                                'default' => '',
429
+			]);
430
+			$table->addColumn('plv_groups_allowed', Types::TEXT, [
431
+				'notnull' => false,
432
+                                'default' => '',
433
+			]);
434
+			$table->addColumn('plv_users_allowed', Types::TEXT, [
435
+				'notnull' => false,
436
+                                'default' => '',
437
+			]);
438
+			$table->addColumn('twl_groups_allowed', Types::TEXT, [
439
+				'notnull' => false,
440
+                                'default' => '',
441
+			]);
442
+			$table->addColumn('twl_users_allowed', Types::TEXT, [
443
+				'notnull' => false,
444
+                                'default' => '',
445
+			]);
446
+			$table->addColumn('flr_groups_allowed', Types::TEXT, [
447
+				'notnull' => false,
448
+                                'default' => '',
449
+			]);
450
+			$table->addColumn('flr_users_allowed', Types::TEXT, [
451
+				'notnull' => false,
452
+                                'default' => '',
453
+			]);
454
+                        $table->setPrimaryKey(['id']);
455
+                        $table->addUniqueIndex(['id']);
456
+		}
457
+
458
+		return $schema;
459
+	}
460
+
461
+}
0 462
new file mode 100644
... ...
@@ -0,0 +1,4532 @@
1
+<?php
2
+/**
3
+ * @copyright 2021 Double Bastion LLC <www.doublebastion.com>
4
+ *
5
+ * @author Double Bastion LLC
6
+ *
7
+ * @license GNU AGPL version 3 or any later version
8
+ *
9
+ * This program is free software; you can redistribute it and/or
10
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
11
+ * License as published by the Free Software Foundation; either
12
+ * version 3 of the License, or any later version.
13
+ *
14
+ * This program is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
18
+ *
19
+ * You should have received a copy of the GNU Affero General Public
20
+ * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
+ *
22
+ */
23
+
24
+declare(strict_types=1);
25
+
26
+namespace OCA\SMSRelentless\Service;
27
+
28
+use OCP\IDBConnection;
29
+use OCP\Security\ICrypto;
30
+use OCP\AppFramework\ApiController;
31
+use OCP\AppFramework\Controller;
32
+use OCP\IRequest;
33
+use OCP\IGroupManager;
34
+use \ReflectionClass;
35
+
36
+class SmsrelentlessService {
37
+
38
+     private $connection;
39
+     private $crypto;
40
+     private $groupManager;
41
+
42
+     public function __construct(IDBConnection $connection, ICrypto $crypto, IGroupManager $groupManager) {
43
+
44
+                $this->connection = $connection;
45
+                $this->crypto = $crypto;
46
+                $this->groupManager = $groupManager;
47
+     }
48
+
49
+
50
+     /**
51
+      * @NoAdminRequired
52
+      *
53
+      */
54
+     public function insertrecsms($userId, $recmessagearr) {
55
+
56
+            $authorDisplayNm = '';
57
+            $internalSender = 0;
58
+
59
+            // Search for the associated Display Name in the previous messages sent from the same phone number, in the 'sms_relent_sent' table
60
+            $recmsgfromprc = '%' . $recmessagearr[2];
61
+            $getdspnmst = $this->connection->prepare('SELECT `from`, `author_displayname` FROM `*PREFIX*sms_relent_sent` WHERE `from` LIKE ?');
62
+            $getdspnmstres = $getdspnmst->execute([$recmsgfromprc]);
63
+
64
+            $dispnamearr = [];
65
+            while ($dspnmstfetched = $getdspnmstres->fetch()) {
66
+                   $dispnamearr[] = $dspnmstfetched['author_displayname'];
67
+            }
68
+	    $getdspnmstres->closeCursor();
69
+
70
+            if ($dispnamearr) {
71
+                $descdspnmarr = array_reverse($dispnamearr);
72
+                $authorDisplayNm = $descdspnmarr[0];
73
+                $internalSender = 1;
74
+            } else { $authorDisplayNm = ''; $internalSender = 0; }
75
+
76
+
77
+            if (!$authorDisplayNm) {
78
+
79
+                // Search for the associated Display Name in the previous messages coming from the same phone number, in the 'sms_relent_received' table
80
+                $getdspnm = $this->connection->prepare('SELECT `from`, `author_displayname` FROM `*PREFIX*sms_relent_received` WHERE `from` = ?');
81
+                $getdspnmres = $getdspnm->execute([$recmessagearr[2]]);
82
+
83
+                $dspnmearr = [];
84
+                while ($dspnmfetched = $getdspnmres->fetch()) {
85
+                       if ($dspnmfetched['author_displayname']) {
86
+                           $dspnmearr[] = $dspnmfetched['author_displayname'];
87
+                       }
88
+                }
89
+	        $getdspnmres->closeCursor();
90
+
91
+                if ($dspnmearr) {
92
+                    $descdisplaynmarr = array_reverse($dspnmearr);
93
+                    $authorDisplayNm = $descdisplaynmarr[0];
94
+                    $internalSender = 0;
95
+                } else { $authorDisplayNm = ''; $internalSender = 0; }
96
+            }
97
+
98
+            // Insert the received message in the 'sms_relent_received' table
99
+            $escapedmessagepre = $recmessagearr[4];
100
+            $escapedmessage = nl2br($escapedmessagepre);
101
+
102
+            $sql = $this->connection->prepare('
103
+				INSERT INTO `*PREFIX*sms_relent_received`
104
+					(`user_id`, `message_id`, `date`, `from`, `to`, `message`, `author_displayname`, `internal_sender`)
105
+				VALUES (?, ?, ?, ?, ?, ?, ?, ?)
106
+			');
107
+	    $sql->execute([$userId, $recmessagearr[0], $recmessagearr[1], $recmessagearr[2], $recmessagearr[3], $escapedmessage, $authorDisplayNm, $internalSender]);
108
+
109
+            // Save a 'new message received' indicator in the 'sms_relent_settings' table, for the (admin) user who received the message
110
+            $newMessageRcd = 1;
111
+	    $sqlupdatenm = $this->connection->prepare('
112
+			UPDATE `*PREFIX*sms_relent_settings`
113
+			SET `new_message_rcd` = ?
114
+	                WHERE `user_id` = ?');
115
+	    $updatenmRes = $sqlupdatenm->execute([$newMessageRcd, $userId]);
116
+	    $updatenmRes->closeCursor();
117
+
118
+
119
+            // Save a 'new message received' indicator in the 'sms_relent_settings' table, for the non-admin users with whom the admin receiving the message shared his API keys
120
+
121
+            // Get the groups and users that were allowed access to the API keys
122
+            $getgrps = $this->connection->prepare('SELECT `user_id`, `tnx_groups_allowed`, `tnx_users_allowed`, `plv_groups_allowed`, `plv_users_allowed`,
123
+                                                  `twl_groups_allowed`, `twl_users_allowed`, `flr_groups_allowed`, `flr_users_allowed` FROM `*PREFIX*sms_relent_subac`
124
+                                                   WHERE `user_id` = ?');
125
+            $getgrpsres = $getgrps->execute([$userId]);
126
+            $getgrpsusr = $getgrpsres->fetch();
127
+            $getgrpsres->closeCursor();
128
+
129
+            if ($getgrpsusr) {
130
+
131
+                if ($getgrpsusr['tnx_users_allowed']) { $tnxusers = explode("|", $getgrpsusr['tnx_users_allowed']); } else { $tnxusers = []; }
132
+                if ($getgrpsusr['plv_users_allowed']) { $plvusers = explode("|", $getgrpsusr['plv_users_allowed']); } else { $plvusers = []; }
133
+                if ($getgrpsusr['twl_users_allowed']) { $twlusers = explode("|", $getgrpsusr['twl_users_allowed']); } else { $twlusers = []; }
134
+                if ($getgrpsusr['flr_users_allowed']) { $flrusers = explode("|", $getgrpsusr['flr_users_allowed']); } else { $flrusers = []; }
135
+
136
+                $allwdusersarr = array_merge($tnxusers, $plvusers, $twlusers, $flrusers);
137
+                $allwdusersunq = array_filter(array_unique($allwdusersarr));
138
+
139
+                if ($getgrpsusr['tnx_groups_allowed']) { $tnxgroups = explode("|", $getgrpsusr['tnx_groups_allowed']); } else { $tnxgroups = []; }
140
+                if ($getgrpsusr['plv_groups_allowed']) { $plvgroups = explode("|", $getgrpsusr['plv_groups_allowed']); } else { $plvgroups = []; }
141
+                if ($getgrpsusr['twl_groups_allowed']) { $twlgroups = explode("|", $getgrpsusr['twl_groups_allowed']); } else { $twlgroups = []; }
142
+                if ($getgrpsusr['flr_groups_allowed']) { $flrgroups = explode("|", $getgrpsusr['flr_groups_allowed']); } else { $flrgroups = []; }
143
+
144
+                $allwdgroupsarr = array_merge($tnxgroups, $plvgroups, $twlgroups, $flrgroups);
145
+                $allwdgroupsunq = array_filter(array_unique($allwdgroupsarr));
146
+
147
+            } else {
148
+                $allwdusersunq = [];
149
+                $allwdgroupsunq = [];
150
+            }
151
+
152
+            // Get the username for each Display Name of the allowed users
153
+            $allwdusersfnl = [];
154
+            foreach ($allwdusersunq as $alwdusrkey => $alwdusrvalue) {
155
+
156
+                         $getacdatausrnm = $this->connection->prepare('SELECT `uid`, `name`, `value` FROM `*PREFIX*accounts_data` WHERE `name` = ? AND `value` = ?');
157
+		         $getacdatausrnmres = $getacdatausrnm->execute(['displayname', $alwdusrvalue]);
158
+		         $acdatausrname = $getacdatausrnmres->fetch();
159
+                         if ($acdatausrname) {
160
+                             $allwdusersfnl[] = $acdatausrname['uid'];
161
+                         }
162
+                         $getacdatausrnmres->closeCursor();
163
+            }
164
+
165
+            // Get the users from all the allowed groups
166
+            $allwdusersgrpmlt = [];
167
+            foreach ($allwdgroupsunq as $prgrpkey => $prgrpvalue) {
168
+
169
+                     // Get all the users that belong to the current group, if the current group is different from 'admin'
170
+                     if ($prgrpvalue != 'admin') {
171
+
172
+                         $getusringroup = $this->connection->prepare('SELECT `gid`, `uid` FROM `*PREFIX*group_user` WHERE `gid` = ?');
173
+		         $getusringroupres = $getusringroup->execute([$prgrpvalue]);
174
+
175
+		         while ($getusrname = $getusringroupres->fetch()) {
176
+                                $allwdusersgrpmlt[] = $getusrname['uid'];
177
+                         }
178
+		         $getusringroupres->closeCursor();
179
+                     }
180
+            }
181
+            $allwdusersgrpfnl = array_unique($allwdusersgrpmlt);
182
+            
183
+            $allusr = array_merge($allwdusersfnl, $allwdusersgrpfnl);
184
+            $allusruniquest = array_unique($allusr);
185
+
186
+            foreach ($allusruniquest as $alwdk => $allwdusr) {
187
+		     $newMsgRcd = 1;
188
+		     $sqlupdatenmsc = $this->connection->prepare('
189
+				UPDATE `*PREFIX*sms_relent_settings`
190
+				SET `new_message_rcd` = ?
191
+			        WHERE `user_id` = ?');
192
+		     $updatenmResc = $sqlupdatenmsc->execute([$newMsgRcd, $allwdusr]);
193
+		     $updatenmResc->closeCursor();
194
+            }
195
+     }
196
+
197
+
198
+     /**
199
+      * @NoAdminRequired
200
+      *
201
+      */
202
+     public function insertsentsms($userId, $displayname, $sentmessagearr) {
203
+
204
+            $msgsentfrompre = explode("+", $sentmessagearr[2]);
205
+            $msgsentfrom = "+" . $msgsentfrompre[1];
206
+
207
+            $textwithnl = nl2br($sentmessagearr[8]);
208
+            $sql = $this->connection->prepare('
209
+				INSERT INTO `*PREFIX*sms_relent_sent`
210
+					(`user_id`, `message_id`, `date`, `from`, `to`, `network`, `price`, `status`, `deliveryreceipt`, `message`, `author_displayname`)
211
+				VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
212
+			');
213
+	    $sql->execute([$userId, $sentmessagearr[0], $sentmessagearr[1], $sentmessagearr[2], $sentmessagearr[3], $sentmessagearr[4], $sentmessagearr[5], $sentmessagearr[6], 
214
+                           $sentmessagearr[7], $textwithnl, $displayname]);
215
+     }
216
+
217
+
218
+     /**
219
+      * @NoAdminRequired
220
+      *
221
+      */
222
+     public function updatedeliverystatustel($ncuserfortelnyxdel, $messageid, $network, $messageprice, $messagestatus, $deliverystatus) {
223
+
224
+	    $sqlupdateds = $this->connection->prepare('
225
+			UPDATE `*PREFIX*sms_relent_sent`
226
+			SET `price` = ?, `status` = ?, `deliveryreceipt` = ?, `network` = ?
227
+                        WHERE `message_id` = ? AND `user_id` = ? ');
228
+	    $updateRes = $sqlupdateds->execute([$messageprice, $messagestatus, $deliverystatus, $network, $messageid, $ncuserfortelnyxdel]);
229
+	    $updateRes->closeCursor();
230
+     }
231
+
232
+
233
+     /**
234
+      * @NoAdminRequired
235
+      *
236
+      */
237
+     public function updatedeliverystatusnex($ncuserforplivodel, $messageid, $networkcode, $messageprice, $mStatus, $deliverystatus) {
238
+
239
+	    $sqlupdatedspl = $this->connection->prepare('
240
+			UPDATE `*PREFIX*sms_relent_sent`
241
+			SET `price` = ?, `deliveryreceipt` = ?, `status` = ?, `network` = ?
242
+                        WHERE `message_id` = ? AND `user_id` = ? ');
243
+	    $updateResdspl = $sqlupdatedspl->execute([$messageprice, $deliverystatus, $mStatus, $networkcode, $messageid, $ncuserforplivodel]);
244
+	    $updateResdspl->closeCursor();
245
+     }
246
+
247
+
248
+     /**
249
+      * @NoAdminRequired
250
+      *
251
+      */
252
+     public function updatedeliverystatustwil($ncuserfortwildel, $messageid, $networkcode, $messageprice, $mStatus, $deliverystatus) {
253
+
254
+	    $sqlupdatedstw = $this->connection->prepare('
255
+			UPDATE `*PREFIX*sms_relent_sent`
256
+			SET `price` = ?, `deliveryreceipt` = ?, `status` = ?, `network` = ?
257
+                        WHERE `message_id` = ? AND `user_id` = ? ');
258
+	    $updateResdstw = $sqlupdatedstw->execute([$messageprice, $deliverystatus, $mStatus, $networkcode, $messageid, $ncuserfortwildel]);
259
+	    $updateResdstw->closeCursor();
260
+     }
261
+
262
+
263
+     /**
264
+      * @NoAdminRequired
265
+      *
266
+      */
267
+     public function updatedeliverystatusflow($ncuserforflowdel, $messageid, $networkcode, $messageprice, $mStatus, $deliverystatus) {
268
+
269
+	    $sqlupdatedsfl = $this->connection->prepare('
270
+			UPDATE `*PREFIX*sms_relent_sent`
271
+			SET `price` = ?, `deliveryreceipt` = ?, `status` = ?, `network` = ?
272
+                        WHERE `message_id` = ? AND `user_id` = ? ');
273
+	    $updateResdsfl = $sqlupdatedsfl->execute([$messageprice, $deliverystatus, $mStatus, $networkcode, $messageid, $ncuserforflowdel]);
274
+	    $updateResdsfl->closeCursor();
275
+     }
276
+
277
+
278
+     /**
279
+      * @NoAdminRequired
280
+      */
281
+     public function getreceivedtable($userId) {
282
+
283
+        // Get the user's preferences from the settings
284
+        $getgamcheckrc = $this->connection->prepare('
285
+		       SELECT `user_id`, `show_all_messages`, `show_display_names`
286
+		       FROM  `*PREFIX*sms_relent_settings` WHERE `user_id` = ?');
287
+        $getgamcheckrcres = $getgamcheckrc->execute([$userId]);
288
+        $getcrgamsrcpref = $getgamcheckrcres->fetch();
289
+        $crgamsrcpref = $getcrgamsrcpref['show_all_messages'];
290
+        $crdnmsrcpref = $getcrgamsrcpref['show_display_names'];
291
+        $getgamcheckrcres->closeCursor();
292
+
293
+
294
+        // Collect the users with whom the current admin is sharing his API keys and whose messages he will be able to see
295
+        if ($crgamsrcpref == 1 && $this->groupManager->isAdmin($userId)) {
296
+
297
+            // Get the groups and users that were allowed access to the API keys
298
+            $getgrps = $this->connection->prepare('SELECT `user_id`, `tnx_groups_allowed`, `tnx_users_allowed`, `plv_groups_allowed`, `plv_users_allowed`,
299
+                                                  `twl_groups_allowed`, `twl_users_allowed`, `flr_groups_allowed`, `flr_users_allowed` FROM `*PREFIX*sms_relent_subac`
300
+                                                   WHERE `user_id` = ?');
301
+            $getgrpsres = $getgrps->execute([$userId]);
302
+            $getgrpsusr = $getgrpsres->fetch();
303
+            $getgrpsres->closeCursor();
304
+
305
+            if ($getgrpsusr) {
306
+
307
+                if ($getgrpsusr['tnx_users_allowed']) { $tnxusers = explode("|", $getgrpsusr['tnx_users_allowed']); } else { $tnxusers = []; }
308
+                if ($getgrpsusr['plv_users_allowed']) { $plvusers = explode("|", $getgrpsusr['plv_users_allowed']); } else { $plvusers = []; }
309
+                if ($getgrpsusr['twl_users_allowed']) { $twlusers = explode("|", $getgrpsusr['twl_users_allowed']); } else { $twlusers = []; }
310
+                if ($getgrpsusr['flr_users_allowed']) { $flrusers = explode("|", $getgrpsusr['flr_users_allowed']); } else { $flrusers = []; }
311
+
312
+                $allwdusersarr = array_merge($tnxusers, $plvusers, $twlusers, $flrusers);
313
+                $allwdusersunq = array_filter(array_unique($allwdusersarr));
314
+
315
+                if ($getgrpsusr['tnx_groups_allowed']) { $tnxgroups = explode("|", $getgrpsusr['tnx_groups_allowed']); } else { $tnxgroups = []; }
316
+                if ($getgrpsusr['plv_groups_allowed']) { $plvgroups = explode("|", $getgrpsusr['plv_groups_allowed']); } else { $plvgroups = []; }
317
+                if ($getgrpsusr['twl_groups_allowed']) { $twlgroups = explode("|", $getgrpsusr['twl_groups_allowed']); } else { $twlgroups = []; }
318
+                if ($getgrpsusr['flr_groups_allowed']) { $flrgroups = explode("|", $getgrpsusr['flr_groups_allowed']); } else { $flrgroups = []; }
319
+
320
+                $allwdgroupsarr = array_merge($tnxgroups, $plvgroups, $twlgroups, $flrgroups);
321
+                $allwdgroupsunq = array_filter(array_unique($allwdgroupsarr));
322
+
323
+            } else {
324
+                $allwdusersunq = [];
325
+                $allwdgroupsunq = [];
326
+            }
327
+
328
+            // Get the username for each Display Name of the allowed users
329
+            $allwdusersfnl = [];
330
+            foreach ($allwdusersunq as $alwdusrkey => $alwdusrvalue) {
331
+
332
+                         $getacdatausrnm = $this->connection->prepare('SELECT `uid`, `name`, `value` FROM `*PREFIX*accounts_data` WHERE `name` = ? AND `value` = ?');
333
+		         $getacdatausrnmres = $getacdatausrnm->execute(['displayname', $alwdusrvalue]);
334
+		         $acdatausrname = $getacdatausrnmres->fetch();
335
+                         if ($acdatausrname) {
336
+                             $allwdusersfnl[] = $acdatausrname['uid'];
337
+                         }
338
+                         $getacdatausrnmres->closeCursor();
339
+            }
340
+
341
+            // Get the users from all the allowed groups
342
+            $allwdusersgrpmlt = [];
343
+            foreach ($allwdgroupsunq as $prgrpkey => $prgrpvalue) {
344
+
345
+                     // Get all the users that belong to the current group, if the current group is different from 'admin'
346
+                     if ($prgrpvalue != 'admin') {
347
+                         $getusringroup = $this->connection->prepare('SELECT `gid`, `uid` FROM `*PREFIX*group_user` WHERE `gid` = ?');
348
+		         $getusringroupres = $getusringroup->execute([$prgrpvalue]);
349
+
350
+		         while ($getusrname = $getusringroupres->fetch()) {
351
+
352
+                                $allwdusersgrpmlt[] = $getusrname['uid'];
353
+                         }
354
+		         $getusringroupres->closeCursor();
355
+                     }
356
+            }
357
+            $allwdusersgrpfnl = array_unique($allwdusersgrpmlt);
358
+            
359
+            $allusr = array_merge($allwdusersfnl, $allwdusersgrpfnl);
360
+            $allusruniquest = array_unique($allusr);
361
+
362
+            if ($allusruniquest) {
363
+                array_unshift($allusruniquest, $userId);
364
+                $allusruniquerc = $allusruniquest;
365
+            } else { $allusruniquerc = [$userId]; }
366
+
367
+            $procardatarcsec = "'" . implode("','", $allusruniquerc) . "'";
368
+
369
+        }
370
+
371
+        // If the user is an admin and he wants to see his messages and the messages of all the users with whom he shares his API keys
372
+        if ($crgamsrcpref == 1 && $this->groupManager->isAdmin($userId)) {
373
+
374
+            if ($crdnmsrcpref == 1) {
375
+
376
+                $rcresult = $this->connection->executeQuery("
377
+                                   SELECT `id`, `user_id`, `message_id`, `date`, `from`, `to`, `message`, `author_displayname`, `internal_sender`
378
+			           FROM `*PREFIX*sms_relent_received` 
379
+                                   WHERE `user_id` IN (" . $procardatarcsec . ")");
380
+
381
+            } else {
382
+
383
+                $rcresult = $this->connection->executeQuery("
384
+			SELECT `id`, `user_id`, `message_id`, `date`, `from`, `to`, `message`, `internal_sender`
385
+			FROM `*PREFIX*sms_relent_received` 
386
+                        WHERE `user_id` IN (" . $procardatarcsec . ")");
387
+            }
388
+
389
+        // If the user is an admin and he wants to see only his messages
390
+        } elseif ($crgamsrcpref == 0 && $this->groupManager->isAdmin($userId)) {
391
+
392
+            if ($crdnmsrcpref == 1) {
393
+	        $getrectable = $this->connection->prepare('
394
+			SELECT `id`, `user_id`, `message_id`, `date`, `from`, `to`, `message`, `author_displayname`, `internal_sender`
395
+			FROM `*PREFIX*sms_relent_received` 
396
+                        WHERE `user_id` = ?');
397
+	        $rcresult = $getrectable->execute([$userId]);
398
+            } else {
399
+	        $getrectable = $this->connection->prepare('
400
+			SELECT `id`, `user_id`, `message_id`, `date`, `from`, `to`, `message`, `internal_sender`
401
+			FROM `*PREFIX*sms_relent_received` 
402
+                        WHERE `user_id` = ?');
403
+	        $rcresult = $getrectable->execute([$userId]);
404
+            }
405
+
406
+        // If the user is not an admin 
407
+        } elseif (!$this->groupManager->isAdmin($userId)) {
408
+
409
+	    // Get the Display Name of the current user
410
+	    $getacdatadn = $this->connection->prepare('SELECT `uid`, `name`, `value` FROM `*PREFIX*accounts_data` WHERE `uid` = ? AND `name` = ?');
411
+	    $getacdatadnres = $getacdatadn->execute([$userId, 'displayname']);
412
+	    $acdatausrdnadm = $getacdatadnres->fetch();
413
+	    $cruserdname = $acdatausrdnadm['value'];
414
+	    $getacdatadnres->closeCursor();
415
+
416
+            // Get the groups to which the current user belongs
417
+            $getusrgrp = $this->connection->prepare('
418
+	          SELECT `gid`, `uid`
419
+	          FROM  `*PREFIX*group_user`
420
+                  WHERE `uid` = ?');
421
+            $getusrgrpres = $getusrgrp->execute([$userId]);
422
+
423
+            $usergrps = [];
424
+            while ($fetchedgrps = $getusrgrpres->fetch()) {
425
+                   $usergrps[] = $fetchedgrps['gid'];
426
+            }
427
+            $getusrgrpres->closeCursor();
428
+
429
+            // Get the restrictions from the 'sms_relent_restrict' table
430
+            $getrestr = $this->connection->prepare('
431
+		       SELECT `phone_number`, `groups`, `users`
432
+		       FROM  `*PREFIX*sms_relent_restrict`');
433
+            $getrestrres = $getrestr->execute();
434
+
435
+            $restrdata = [];
436
+            while ($restrfetched = $getrestrres->fetch()) {
437
+                   $restrdata[] = $restrfetched;
438
+            }
439
+            $getrestrres->closeCursor();
440
+
441
+            // Get the phone numbers that the user is allowed/not allowed to use
442
+            if ($restrdata) {
443
+
444
+                $restrPhoneNmbrs = [];
445
+                $allowedPhoneNmbrs = [];
446
+                foreach ($restrdata as $rskey => $rsvalue) {
447
+
448
+                         $chck = 0;
449
+                         $restrgrparr = explode("|", $rsvalue['groups']);
450
+                         foreach ($restrgrparr as $rkey => $rvalue) {
451
+                                  if ($rvalue) {
452
+                                      if (strpos(implode("|", $usergrps), $rvalue) !== false) { $chck++; }
453
+                                  }
454
+                         }
455
+                         if (strpos($rsvalue['users'], $cruserdname) !== false) { $chck++; }
456
+
457
+                         if ($chck == 0) {
458
+                             $restrPhoneNmbrs[] = $rsvalue['phone_number'];
459
+                         }
460
+                }
461
+
462
+		$allowedPhNmbrs = $this->getsmsnumbers($userId);
463
+
464
+		foreach ($allowedPhNmbrs as $apnkey => $apnvalue) {
465
+			 $crphnmbr = explode(": ", $apnvalue);
466
+			 if ($crphnmbr[0] == 'Tx') {
467
+			     $allowedPhoneNmbrs[] = 'Telnyx: ' . $crphnmbr[1];
468
+			 } elseif ($crphnmbr[0] == 'Pl') {
469
+			     $allowedPhoneNmbrs[] = 'Plivo: ' . $crphnmbr[1];
470
+			 } elseif ($crphnmbr[0] == 'Tw') {
471
+			     $allowedPhoneNmbrs[] = 'Twilio: ' . $crphnmbr[1];
472
+			 } elseif ($crphnmbr[0] == 'Fl') {
473
+			     $allowedPhoneNmbrs[] = 'Flowroute: ' . $crphnmbr[1];
474
+			 }
475
+		}
476
+
477
+                $procalwduid = $allowedPhoneNmbrs;
478
+                $procalwduidsec = "'" . implode("','", $procalwduid) . "'";
479
+
480
+                if ($crdnmsrcpref == 1) {
481
+
482
+                    if ($procalwduidsec != "''") {
483
+
484
+                        $rcresult = $this->connection->executeQuery("
485
+			                   SELECT `id`, `user_id`, `message_id`, `date`, `from`, `to`, `message`, `author_displayname`, `internal_sender`
486
+			                   FROM `*PREFIX*sms_relent_received`
487
+			                   WHERE `user_id` = '$userId' OR `to` IN (" . $procalwduidsec . ")");
488
+
489
+                    } else {
490
+
491
+	                $getrectable = $this->connection->prepare('
492
+			    SELECT `id`, `user_id`, `message_id`, `date`, `from`, `to`, `message`, `author_displayname`, `internal_sender`
493
+			    FROM `*PREFIX*sms_relent_received`
494
+			    WHERE `user_id` = ?');
495
+	                $rcresult = $getrectable->execute([$userId]);
496
+                    }
497
+
498
+                } else {
499
+
500
+                    if ($procalwduidsec) {
501
+
502
+                        $rcresult = $this->connection->executeQuery("
503
+			    SELECT `id`, `user_id`, `message_id`, `date`, `from`, `to`, `message`, `internal_sender`
504
+			    FROM `*PREFIX*sms_relent_received`
505
+			    WHERE `user_id` = '$userId' OR `to` IN (" . $procalwduidsec . ")");
506
+                    } else {
507
+	                $getrectable = $this->connection->prepare('
508
+			    SELECT `id`, `user_id`, `message_id`, `date`, `from`, `to`, `message`, `internal_sender`
509
+			    FROM `*PREFIX*sms_relent_received`
510
+			    WHERE `user_id` = ?');
511
+	                $rcresult = $getrectable->execute([$userId]);
512
+                    }
513
+                }
514
+
515
+            } else {
516
+
517
+		$allowedPhNmbrs = $this->getsmsnumbers($userId);
518
+
519
+		foreach ($allowedPhNmbrs as $apnkey => $apnvalue) {
520
+			 $crphnmbr = explode(": ", $apnvalue);
521
+			 if ($crphnmbr[0] == 'Tx') {
522
+			     $allowedPhoneNmbrs[] = 'Telnyx: ' . $crphnmbr[1];
523
+			 } elseif ($crphnmbr[0] == 'Pl') {
524
+			     $allowedPhoneNmbrs[] = 'Plivo: ' . $crphnmbr[1];
525
+			 } elseif ($crphnmbr[0] == 'Tw') {
526
+			     $allowedPhoneNmbrs[] = 'Twilio: ' . $crphnmbr[1];
527
+			 } elseif ($crphnmbr[0] == 'Fl') {
528
+			     $allowedPhoneNmbrs[] = 'Flowroute: ' . $crphnmbr[1];
529
+			 }
530
+		}
531
+
532
+                $procalwduid = $allowedPhoneNmbrs;
533
+                $procalwduidsec = "'" . implode("','", $procalwduid) . "'";
534
+
535
+                if ($crdnmsrcpref == 1) {
536
+
537
+                    if ($procalwduidsec != "''") {
538
+
539
+                        $rcresult = $this->connection->executeQuery("
540
+			                   SELECT `id`, `user_id`, `message_id`, `date`, `from`, `to`, `message`, `author_displayname`, `internal_sender`
541
+			                   FROM `*PREFIX*sms_relent_received`
542
+			                   WHERE `user_id` = '$userId' OR `to` IN (" . $procalwduidsec . ")");
543
+
544
+                    } else {
545
+
546
+	                $getrectable = $this->connection->prepare('
547
+			    SELECT `id`, `user_id`, `message_id`, `date`, `from`, `to`, `message`, `author_displayname`, `internal_sender`
548
+			    FROM `*PREFIX*sms_relent_received`
549
+			    WHERE `user_id` = ?');
550
+	                $rcresult = $getrectable->execute([$userId]);
551
+                    }
552
+
553
+                } else {
554
+
555
+                    if ($procalwduidsec) {
556
+
557
+                        $rcresult = $this->connection->executeQuery("
558
+			    SELECT `id`, `user_id`, `message_id`, `date`, `from`, `to`, `message`, `internal_sender`
559
+			    FROM `*PREFIX*sms_relent_received`
560
+			    WHERE `user_id` = '$userId' OR `to` IN (" . $procalwduidsec . ")");
561
+                    } else {
562
+	                $getrectable = $this->connection->prepare('
563
+			    SELECT `id`, `user_id`, `message_id`, `date`, `from`, `to`, `message`, `internal_sender`
564
+			    FROM `*PREFIX*sms_relent_received`
565
+			    WHERE `user_id` = ?');
566
+	                $rcresult = $getrectable->execute([$userId]);
567
+                    }
568
+                }
569
+            }
570
+        }
571
+
572
+        $recdatatable = [];
573
+        while ($rowfetched = $rcresult->fetch()) {
574
+               $recdatatable[] = $rowfetched;
575
+        }
576
+	$rcresult->closeCursor();
577
+
578
+        $recdatafromdb = $recdatatable;
579
+
580
+
581
+        if ($this->groupManager->isAdmin($userId)) {
582
+
583
+              $recdatafdb = ['datarows' => $recdatafromdb, 'showdispnm' => $crdnmsrcpref];
584
+              return $recdatafdb;
585
+
586
+        } else {
587
+
588
+            if ($restrdata) {
589
+
590
+                // Clean the 'not allowed' phone numbers from tags
591
+                $restrPhfin = [];
592
+                foreach ($restrPhoneNmbrs as $phkey => $phvalue) {
593
+
594
+                    $restrpharr = explode(": ", $phvalue);
595
+                    $restrPhfin[] = $restrpharr[1];
596
+                }
597
+
598
+                // Assemble the array of message rows that excludes the rows for the 'not allowed' phone numbers
599
+                foreach ($recdatafromdb as $mdkey => $mdvalue) {
600
+
601
+                    if (str_contains($mdvalue['to'], "+")) {
602
+                        $fromnmbrarr = explode("+", $mdvalue['to']);
603
+                        if (in_array("+" . $fromnmbrarr[1], $restrPhfin)) {
604
+                            unset($recdatafromdb[$mdkey]);
605
+                        }
606
+                    } else {
607
+                        $tonmbrarr = explode(": ", $mdvalue['to']);
608
+                        if (count($tonmbrarr) == 2) {
609
+                            $tonmbrtbcmprd = $tonmbrarr[1];
610
+                        } else {
611
+                            $tonmbrtbcmprd = $tonmbrarr[0];
612
+                        }
613
+                        if (in_array($tonmbrtbcmprd, $restrPhfin)) {
614
+                            unset($recdatafromdb[$mdkey]);
615
+                        }
616
+                    }
617
+                }
618
+
619
+                $recdatafdbproc = array_values($recdatafromdb);
620
+
621
+                $recdataproc = ['datarows' => $recdatafdbproc, 'showdispnm' => $crdnmsrcpref];
622
+                return $recdataproc;
623
+
624
+            } else {
625
+
626
+                $recdatafdb = ['datarows' => $recdatafromdb, 'showdispnm' => $crdnmsrcpref];
627
+                return $recdatafdb;
628
+            }
629
+        }
630
+     }
631
+
632
+
633
+     /**
634
+      * @NoAdminRequired
635
+      */
636
+     public function getreceivedtablefordel($userId) {
637
+
638
+        if ($this->groupManager->isAdmin($userId)) {
639
+
640
+            $getrecfordl = $this->connection->prepare('
641
+			SELECT `id`, `user_id`, `message_id`, `date`, `from`, `to`, `message`, `author_displayname`, `internal_sender`
642
+			FROM  `*PREFIX*sms_relent_received`
643
+			WHERE `user_id` = ?');
644
+	    $resultdl = $getrecfordl->execute([$userId]);
645
+
646
+            $recdatatable = [];
647
+            while ($rowfetched = $resultdl->fetch()) {
648
+                   $recdatatable[] = $rowfetched;
649
+            }
650
+            $resultdl->closeCursor();
651
+
652
+            $recdatafromdb = $recdatatable;
653
+
654
+            return $recdatafromdb;
655
+
656
+        } else { return "not permitted"; }
657
+     }
658
+
659
+
660
+     /**
661
+      * @NoAdminRequired
662
+      */
663
+     public function removerecrows($userId, $recmessagedbIDs) {
664
+
665
+        foreach ($recmessagedbIDs as $key => $rowtodel) {
666
+		 $query = $this->connection->prepare('
667
+		       DELETE FROM `*PREFIX*sms_relent_received`
668
+		       WHERE `id` = ?');
669
+		 $deleteResult = $query->execute([$rowtodel]);
670
+		 $deleteResult->closeCursor();
671
+        }
672
+
673
+	$sqlupdate = $this->connection->prepare('
674
+                  SET @resetrec = 0;
675
+		  UPDATE `*PREFIX*sms_relent_received`
676
+		  SET `id` = @resetrec := @resetrec + 1;
677
+                  ALTER TABLE `*PREFIX*sms_relent_received` auto_increment=1;');
678
+	$updateRes = $sqlupdate->execute();
679
+	$updateRes->closeCursor();
680
+     }
681
+
682
+
683
+     /**
684
+      * @NoAdminRequired
685
+      */
686
+     public function getsenttable($userId) {
687
+
688
+        // Get the user's preferences from the settings
689
+        $getgamcheck = $this->connection->prepare('
690
+		       SELECT `user_id`, `show_all_messages`, `show_display_names`
691
+		       FROM  `*PREFIX*sms_relent_settings` WHERE `user_id` = ?');
692
+        $getgamcheckres = $getgamcheck->execute([$userId]);
693
+        $getcrgamspref = $getgamcheckres->fetch();
694
+        $crgamspref = $getcrgamspref['show_all_messages'];
695
+        $crdnamespref = $getcrgamspref['show_display_names'];
696
+        $getgamcheckres->closeCursor();
697
+
698
+
699
+        // Collect the users with whom the current admin is sharing his API keys and whose messages he will be able to see
700
+        if ($crgamspref == 1 && $this->groupManager->isAdmin($userId)) {
701
+
702
+            // Get the groups and users that were allowed access to the API keys
703
+            $getgrps = $this->connection->prepare('SELECT `user_id`, `tnx_groups_allowed`, `tnx_users_allowed`, `plv_groups_allowed`, `plv_users_allowed`,
704
+                                                  `twl_groups_allowed`, `twl_users_allowed`, `flr_groups_allowed`, `flr_users_allowed` FROM `*PREFIX*sms_relent_subac`
705
+                                                   WHERE `user_id` = ?');
706
+            $getgrpsres = $getgrps->execute([$userId]);
707
+            $getgrpsusr = $getgrpsres->fetch();
708
+            $getgrpsres->closeCursor();
709
+
710
+            if ($getgrpsusr) {
711
+
712
+                if ($getgrpsusr['tnx_users_allowed']) { $tnxusers = explode("|", $getgrpsusr['tnx_users_allowed']); } else { $tnxusers = []; }
713
+                if ($getgrpsusr['plv_users_allowed']) { $plvusers = explode("|", $getgrpsusr['plv_users_allowed']); } else { $plvusers = []; }
714
+                if ($getgrpsusr['twl_users_allowed']) { $twlusers = explode("|", $getgrpsusr['twl_users_allowed']); } else { $twlusers = []; }
715
+                if ($getgrpsusr['flr_users_allowed']) { $flrusers = explode("|", $getgrpsusr['flr_users_allowed']); } else { $flrusers = []; }
716
+
717
+                $allwdusersarr = array_merge($tnxusers, $plvusers, $twlusers, $flrusers);
718
+                $allwdusersunq = array_filter(array_unique($allwdusersarr));
719
+
720
+                if ($getgrpsusr['tnx_groups_allowed']) { $tnxgroups = explode("|", $getgrpsusr['tnx_groups_allowed']); } else { $tnxgroups = []; }
721
+                if ($getgrpsusr['plv_groups_allowed']) { $plvgroups = explode("|", $getgrpsusr['plv_groups_allowed']); } else { $plvgroups = []; }
722
+                if ($getgrpsusr['twl_groups_allowed']) { $twlgroups = explode("|", $getgrpsusr['twl_groups_allowed']); } else { $twlgroups = []; }
723
+                if ($getgrpsusr['flr_groups_allowed']) { $flrgroups = explode("|", $getgrpsusr['flr_groups_allowed']); } else { $flrgroups = []; }
724
+
725
+                $allwdgroupsarr = array_merge($tnxgroups, $plvgroups, $twlgroups, $flrgroups);
726
+                $allwdgroupsunq = array_filter(array_unique($allwdgroupsarr));
727
+
728
+            } else {
729
+                $allwdusersunq = [];
730
+                $allwdgroupsunq = [];
731
+            }
732
+
733
+            // Get the username for each Display Name of the allowed users
734
+            $allwdusersfnl = [];
735
+            foreach ($allwdusersunq as $alwdusrkey => $alwdusrvalue) {
736
+
737
+                         $getacdatausrnm = $this->connection->prepare('SELECT `uid`, `name`, `value` FROM `*PREFIX*accounts_data` WHERE `name` = ? AND `value` = ?');
738
+		         $getacdatausrnmres = $getacdatausrnm->execute(['displayname', $alwdusrvalue]);
739
+		         $acdatausrname = $getacdatausrnmres->fetch();
740
+                         if ($acdatausrname) {
741
+                             $allwdusersfnl[] = $acdatausrname['uid'];
742
+                         }
743
+                         $getacdatausrnmres->closeCursor();
744
+            }
745
+
746
+            // Get the users from all the allowed groups
747
+            $allwdusersgrpmlt = [];
748
+            foreach ($allwdgroupsunq as $prgrpkey => $prgrpvalue) {
749
+
750
+                     // Get all the users that belong to the current group, if the current group is different from 'admin'
751
+                     if ($prgrpvalue != 'admin') {
752
+                         $getusringroup = $this->connection->prepare('SELECT `gid`, `uid` FROM `*PREFIX*group_user` WHERE `gid` = ?');
753
+		         $getusringroupres = $getusringroup->execute([$prgrpvalue]);
754
+
755
+		         while ($getusrname = $getusringroupres->fetch()) {
756
+
757
+                                $allwdusersgrpmlt[] = $getusrname['uid'];
758
+                         }
759
+		         $getusringroupres->closeCursor();
760
+                     }
761
+            }
762
+            $allwdusersgrpfnl = array_unique($allwdusersgrpmlt);
763
+            
764
+            $allusr = array_merge($allwdusersfnl, $allwdusersgrpfnl);
765
+            $allusruniquest = array_unique($allusr);
766
+
767
+            if ($allusruniquest) {
768
+                array_unshift($allusruniquest, $userId);
769
+                $allusrunique = $allusruniquest;
770
+            } else { $allusrunique = [$userId]; }
771
+
772
+            $allusruniquesec = "'" . implode("','", $allusrunique) . "'";
773
+        }
774
+
775
+        // If the user is an admin and he wants to see his messages and the messages of all the users with whom he shares his API keys
776
+        if ($crgamspref == 1 && $this->groupManager->isAdmin($userId)) {
777
+
778
+            if ($crdnamespref == 1) {
779
+
780
+                $resultsent = $this->connection->executeQuery("
781
+                       SELECT `id`, `user_id`, `message_id`, `date`, `from`, `to`, `network`, `price`, `status`, `deliveryreceipt`, `message`, `author_displayname`
782
+		       FROM  `*PREFIX*sms_relent_sent` 
783
+                       WHERE `user_id` IN (" . $allusruniquesec . ")");
784
+            } else {
785
+
786
+                $resultsent = $this->connection->executeQuery("
787
+                       SELECT `id`, `user_id`, `message_id`, `date`, `from`, `to`, `network`, `price`, `status`, `deliveryreceipt`, `message`
788
+		       FROM  `*PREFIX*sms_relent_sent`
789
+                       WHERE `user_id` IN (" . $allusruniquesec . ")");
790
+            }
791
+
792
+        // If the user is an admin and he wants to see only his messages
793
+        } elseif ($crgamspref == 0 && $this->groupManager->isAdmin($userId)) {
794
+
795
+            if ($crdnamespref == 1) {
796
+                $getsenttbl = $this->connection->prepare('
797
+		       SELECT `id`, `user_id`, `message_id`, `date`, `from`, `to`, `network`, `price`, `status`, `deliveryreceipt`, `message`, `author_displayname`
798
+		       FROM  `*PREFIX*sms_relent_sent` 
799
+                       WHERE `user_id` = ?');
800
+                $resultsent = $getsenttbl->execute([$userId]);
801
+            } else {
802
+                $getsenttbl = $this->connection->prepare('
803
+		       SELECT `id`, `user_id`, `message_id`, `date`, `from`, `to`, `network`, `price`, `status`, `deliveryreceipt`, `message`
804
+		       FROM  `*PREFIX*sms_relent_sent` 
805
+                       WHERE `user_id` = ?');
806
+                $resultsent = $getsenttbl->execute([$userId]);
807
+            }
808
+
809
+        // If the user is not an admin 
810
+        } elseif (!$this->groupManager->isAdmin($userId)) {
811
+
812
+	    // Get the Display Name of the current user
813
+	    $getacdatadn = $this->connection->prepare('SELECT `uid`, `name`, `value` FROM `*PREFIX*accounts_data` WHERE `uid` = ? AND `name` = ?');
814
+	    $getacdatadnres = $getacdatadn->execute([$userId, 'displayname']);
815
+	    $acdatausrdnadm = $getacdatadnres->fetch();
816
+	    $cruserdname = $acdatausrdnadm['value'];
817
+	    $getacdatadnres->closeCursor();
818
+
819
+            // Get the groups to which the current user belongs
820
+            $getusrgrp = $this->connection->prepare('
821
+	          SELECT `gid`, `uid`
822
+	          FROM  `*PREFIX*group_user`
823
+                  WHERE `uid` = ?');
824
+            $getusrgrpres = $getusrgrp->execute([$userId]);
825
+
826
+            $usergrps = [];
827
+            while ($fetchedgrps = $getusrgrpres->fetch()) {
828
+                   $usergrps[] = $fetchedgrps['gid'];
829
+            }
830
+            $getusrgrpres->closeCursor();
831
+
832
+            // Get the restrictions from the 'sms_relent_restrict' table
833
+            $getrestr = $this->connection->prepare('
834
+		       SELECT `phone_number`, `groups`, `users`
835
+		       FROM  `*PREFIX*sms_relent_restrict`');
836
+            $getrestrres = $getrestr->execute();
837
+
838
+            $restrdata = [];
839
+            while ($restrfetched = $getrestrres->fetch()) {
840
+                   $restrdata[] = $restrfetched;
841
+            }
842
+            $getrestrres->closeCursor();
843
+
844
+            // Get the phone numbers that the user is allowed/not allowed to use
845
+            if ($restrdata) {
846
+
847
+                $restrPhoneNmbrs = [];
848
+                $allowedPhoneNmbrs = [];
849
+                foreach ($restrdata as $rskey => $rsvalue) {
850
+
851
+                         $chck = 0;
852
+                         $restrgrparr = explode("|", $rsvalue['groups']);
853
+                         foreach ($restrgrparr as $rkey => $rvalue) {
854
+                                  if ($rvalue) {
855
+                                      if (strpos(implode("|", $usergrps), $rvalue) !== false) { $chck++; }
856
+                                  }
857
+                         }
858
+                         if (strpos($rsvalue['users'], $cruserdname) !== false) { $chck++; }
859
+
860
+                         if ($chck == 0) { 
861
+                             $restrPhoneNmbrs[] = $rsvalue['phone_number']; 
862
+                         }
863
+                }
864
+
865
+		$allowedPhNmbrs = $this->getsmsnumbers($userId);
866
+
867
+		foreach ($allowedPhNmbrs as $apnkey => $apnvalue) {
868
+			 $crphnmbr = explode(": ", $apnvalue);
869
+			 if ($crphnmbr[0] == 'Tx') {
870
+			     $allowedPhoneNmbrs[] = 'Telnyx: ' . $crphnmbr[1];
871
+			 } elseif ($crphnmbr[0] == 'Pl') {
872
+			     $allowedPhoneNmbrs[] = 'Plivo: ' . $crphnmbr[1];
873
+			 } elseif ($crphnmbr[0] == 'Tw') {
874
+			     $allowedPhoneNmbrs[] = 'Twilio: ' . $crphnmbr[1];
875
+			 } elseif ($crphnmbr[0] == 'Fl') {
876
+			     $allowedPhoneNmbrs[] = 'Flowroute: ' . $crphnmbr[1];
877
+			 }
878
+		}
879
+
880
+                $procalwduid = $allowedPhoneNmbrs;
881
+                $procalwduidsec = "'" . implode("','", $procalwduid) . "'";
882
+
883
+                if ($crdnamespref == 1) {
884
+                    if ($procalwduidsec != "''") {
885
+
886
+                        $resultsent = $this->connection->executeQuery("
887
+		            SELECT `id`, `user_id`, `message_id`, `date`, `from`, `to`, `network`, `price`, `status`, `deliveryreceipt`, `message`, `author_displayname`
888
+		            FROM `*PREFIX*sms_relent_sent`
889
+			    WHERE `user_id` = '$userId' OR `from` IN (" . $procalwduidsec . ")");
890
+                    } else {
891
+	                $getsenttbl = $this->connection->prepare('
892
+		            SELECT `id`, `user_id`, `message_id`, `date`, `from`, `to`, `network`, `price`, `status`, `deliveryreceipt`, `message`, `author_displayname`
893
+		            FROM `*PREFIX*sms_relent_sent`
894
+			    WHERE `user_id` = ?');
895
+	                $resultsent = $getsenttbl->execute([$userId]);
896
+                    }
897
+                } else {
898
+                    if ($procalwduidsec != "''") {
899
+
900
+                        $resultsent = $this->connection->executeQuery("
901
+		            SELECT `id`, `user_id`, `message_id`, `date`, `from`, `to`, `network`, `price`, `status`, `deliveryreceipt`, `message`
902
+		            FROM `*PREFIX*sms_relent_sent`
903
+			    WHERE `user_id` = '$userId' OR `from` IN (" . $procalwduidsec . ")");
904
+
905
+                    } else {
906
+	                $getsenttbl = $this->connection->prepare('
907
+		            SELECT `id`, `user_id`, `message_id`, `date`, `from`, `to`, `network`, `price`, `status`, `deliveryreceipt`, `message`
908
+		            FROM `*PREFIX*sms_relent_sent`
909
+			    WHERE `user_id` = ?');
910
+	                $resultsent = $getsenttbl->execute([$userId]);
911
+                    }
912
+                }
913
+
914
+            } else {
915
+
916
+                if ($crdnamespref == 1) {
917
+                    $getsenttbl = $this->connection->prepare('
918
+		       SELECT `id`, `user_id`, `message_id`, `date`, `from`, `to`, `network`, `price`, `status`, `deliveryreceipt`, `message`, `author_displayname`
919
+		       FROM `*PREFIX*sms_relent_sent`
920
+		       WHERE `user_id` = ?');
921
+                    $resultsent = $getsenttbl->execute([$userId]);
922
+                } else {
923
+                    $getsenttbl = $this->connection->prepare('
924
+		       SELECT `id`, `user_id`, `message_id`, `date`, `from`, `to`, `network`, `price`, `status`, `deliveryreceipt`, `message`
925
+		       FROM `*PREFIX*sms_relent_sent`
926
+		       WHERE `user_id` = ?');
927
+                    $resultsent = $getsenttbl->execute([$userId]);
928
+                }
929
+            }
930
+        }
931
+
932
+
933
+        $sentdatatable = [];
934
+        while ($rowfetched = $resultsent->fetch()){
935
+               $sentdatatable[] = $rowfetched;
936
+        }
937
+        $resultsent->closeCursor();
938
+
939
+        $sentdatafromdb = $sentdatatable;
940
+
941
+
942
+        if ($this->groupManager->isAdmin($userId)) {
943
+
944
+            $sentdatafdb = ['datarows' => $sentdatafromdb, 'showdispnm' => $crdnamespref];
945
+            return $sentdatafdb;
946
+
947
+        } else {
948
+
949
+            if ($restrdata) {
950
+
951
+                // Clean the phone numbers from tags
952
+                $restrPhfin = [];
953
+                foreach ($restrPhoneNmbrs as $phkey => $phvalue) {
954
+
955
+                    $restrpharr = explode(": ", $phvalue);
956
+                    $restrPhfin[] = $restrpharr[1];
957
+                }
958
+
959
+                // Assemble the array of message rows that excludes the rows for the restricted phone numbers
960
+                foreach ($sentdatafromdb as $smdkey => $smdvalue) {
961
+
962
+                    if (str_contains($smdvalue['from'], "+")) {
963
+                        $fromnmbrarr = explode("+", $smdvalue['from']);
964
+                        if (in_array("+" . $fromnmbrarr[1], $restrPhfin)) {
965
+                            unset($sentdatafromdb[$smdkey]);
966
+                        }
967
+                    } else {
968
+                        $frmnmbrarr = explode(": ", $smdvalue['from']);
969
+                        if (count($frmnmbrarr) == 2) {
970
+                            $nmbtbcmprd = $frmnmbrarr[1];
971
+                        } else { 
972
+                            $nmbtbcmprd = $frmnmbrarr[0];
973
+                        }
974
+
975
+                        if (in_array($nmbtbcmprd, $restrPhfin)) {
976
+                            unset($sentdatafromdb[$smdkey]);
977
+                        }
978
+                    }
979
+                }
980
+
981
+                $sentdatadbproc = array_values($sentdatafromdb);
982
+
983
+                $sentdatafdb = ['datarows' => $sentdatadbproc, 'showdispnm' => $crdnamespref];
984
+                return $sentdatafdb;
985
+
986
+            } else {
987
+
988
+                $sentdatafdb = ['datarows' => $sentdatafromdb, 'showdispnm' => $crdnamespref];
989
+                return $sentdatafdb;
990
+            }
991
+        }
992
+     }
993
+
994
+
995
+     /**
996
+      * @NoAdminRequired
997
+      */
998
+     public function getsenttablefordel($userId) {
999
+
1000
+        if ($this->groupManager->isAdmin($userId)) {
1001
+
1002
+            $getsenttbldel = $this->connection->prepare('
1003
+		          SELECT `id`, `user_id`, `message_id`, `date`, `from`, `to`, `network`, `price`, `status`, `deliveryreceipt`, `message`, `author_displayname`
1004
+		          FROM  `*PREFIX*sms_relent_sent`
1005
+		          WHERE `user_id` = ?');
1006
+            $resultsentdl = $getsenttbldel->execute([$userId]);
1007
+
1008
+            $sentdatatable = [];
1009
+            while ($rowfetched = $resultsentdl->fetch()){
1010
+                   $sentdatatable[] = $rowfetched;
1011
+            }
1012
+            $resultsentdl->closeCursor();
1013
+
1014
+            $sentdatafromdb = $sentdatatable;
1015
+
1016
+            return $sentdatafromdb;
1017
+
1018
+        } else { return "not permitted"; }
1019
+     }
1020
+
1021
+
1022
+     /**
1023
+      * @NoAdminRequired
1024
+      */
1025
+     public function removesentrows($userId, $sentmessagedbIDs) {
1026
+
1027
+        foreach ($sentmessagedbIDs as $key => $sentrowtodel) {
1028
+		 $query = $this->connection->prepare('
1029
+		       DELETE FROM `*PREFIX*sms_relent_sent`
1030
+		       WHERE `id` = ?');
1031
+		 $deleteResult = $query->execute([$sentrowtodel]);
1032
+		 $deleteResult->closeCursor();
1033
+        }
1034
+
1035
+	$sqlupdate = $this->connection->prepare('
1036
+                  SET @resetsent = 0;
1037
+		  UPDATE `*PREFIX*sms_relent_sent`
1038
+		  SET `id` = @resetsent := @resetsent + 1;
1039
+                  ALTER TABLE `*PREFIX*sms_relent_sent` auto_increment=1;');
1040
+	$updateRes = $sqlupdate->execute();
1041
+	$updateRes->closeCursor();
1042
+     }
1043
+
1044
+
1045
+     /**
1046
+      * @NoAdminRequired
1047
+      */
1048
+     public function getgroupedtable($userId) {
1049
+
1050
+
1051
+        // Get the user's preferences from the settings
1052
+        $getpref = $this->connection->prepare('
1053
+		       SELECT `user_id`, `show_all_messages`
1054
+		       FROM  `*PREFIX*sms_relent_settings` WHERE `user_id` = ?');
1055
+        $getprefres = $getpref->execute([$userId]);
1056
+        $getprefresdata = $getprefres->fetch();
1057
+        $crsampref = $getprefresdata['show_all_messages'];
1058
+        $getprefres->closeCursor();
1059
+
1060
+
1061
+        // Collect the users with whom the current admin is sharing his API keys and whose messages he will be able to see
1062
+        if ($crsampref == 1 && $this->groupManager->isAdmin($userId)) {
1063
+
1064
+            // Get the groups and users that were allowed access to the API keys
1065
+            $getgrps = $this->connection->prepare('SELECT `user_id`, `tnx_groups_allowed`, `tnx_users_allowed`, `plv_groups_allowed`, `plv_users_allowed`,
1066
+                                                  `twl_groups_allowed`, `twl_users_allowed`, `flr_groups_allowed`, `flr_users_allowed` FROM `*PREFIX*sms_relent_subac`
1067
+                                                   WHERE `user_id` = ?');
1068
+            $getgrpsres = $getgrps->execute([$userId]);
1069
+            $getgrpsusr = $getgrpsres->fetch();
1070
+            $getgrpsres->closeCursor();
1071
+
1072
+            if ($getgrpsusr) {
1073
+
1074
+                if ($getgrpsusr['tnx_users_allowed']) { $tnxusers = explode("|", $getgrpsusr['tnx_users_allowed']); } else { $tnxusers = []; }
1075
+                if ($getgrpsusr['plv_users_allowed']) { $plvusers = explode("|", $getgrpsusr['plv_users_allowed']); } else { $plvusers = []; }
1076
+                if ($getgrpsusr['twl_users_allowed']) { $twlusers = explode("|", $getgrpsusr['twl_users_allowed']); } else { $twlusers = []; }
1077
+                if ($getgrpsusr['flr_users_allowed']) { $flrusers = explode("|", $getgrpsusr['flr_users_allowed']); } else { $flrusers = []; }
1078
+
1079
+                $allwdusersarr = array_merge($tnxusers, $plvusers, $twlusers, $flrusers);
1080
+                $allwdusersunq = array_filter(array_unique($allwdusersarr));
1081
+
1082
+                if ($getgrpsusr['tnx_groups_allowed']) { $tnxgroups = explode("|", $getgrpsusr['tnx_groups_allowed']); } else { $tnxgroups = []; }
1083
+                if ($getgrpsusr['plv_groups_allowed']) { $plvgroups = explode("|", $getgrpsusr['plv_groups_allowed']); } else { $plvgroups = []; }
1084
+                if ($getgrpsusr['twl_groups_allowed']) { $twlgroups = explode("|", $getgrpsusr['twl_groups_allowed']); } else { $twlgroups = []; }
1085
+                if ($getgrpsusr['flr_groups_allowed']) { $flrgroups = explode("|", $getgrpsusr['flr_groups_allowed']); } else { $flrgroups = []; }
1086
+
1087
+                $allwdgroupsarr = array_merge($tnxgroups, $plvgroups, $twlgroups, $flrgroups);
1088
+                $allwdgroupsunq = array_filter(array_unique($allwdgroupsarr));
1089
+
1090
+            } else {
1091
+                $allwdusersunq = [];
1092
+                $allwdgroupsunq = [];
1093
+            }
1094
+
1095
+            // Get the username for each Display Name of the allowed users
1096
+            $allwdusersfnl = [];
1097
+            foreach ($allwdusersunq as $alwdusrkey => $alwdusrvalue) {
1098
+
1099
+                         $getacdatausrnm = $this->connection->prepare('SELECT `uid`, `name`, `value` FROM `*PREFIX*accounts_data` WHERE `name` = ? AND `value` = ?');
1100
+		         $getacdatausrnmres = $getacdatausrnm->execute(['displayname', $alwdusrvalue]);
1101
+		         $acdatausrname = $getacdatausrnmres->fetch();
1102
+                         if ($acdatausrname) {
1103
+                             $allwdusersfnl[] = $acdatausrname['uid'];
1104
+                         }
1105
+                         $getacdatausrnmres->closeCursor();
1106
+            }
1107
+
1108
+            // Get the users from all the allowed groups
1109
+            $allwdusersgrpmlt = [];
1110
+            foreach ($allwdgroupsunq as $prgrpkey => $prgrpvalue) {
1111
+
1112
+                     // Get all the users that belong to the current group, if the current group is different from 'admin'
1113
+                     if ($prgrpvalue != 'admin') {
1114
+                         $getusringroup = $this->connection->prepare('SELECT `gid`, `uid` FROM `*PREFIX*group_user` WHERE `gid` = ?');
1115
+		         $getusringroupres = $getusringroup->execute([$prgrpvalue]);
1116
+
1117
+		         while ($getusrname = $getusringroupres->fetch()) {
1118
+
1119
+                                $allwdusersgrpmlt[] = $getusrname['uid'];
1120
+                         }
1121
+		         $getusringroupres->closeCursor();
1122
+                     }
1123
+            }
1124
+            $allwdusersgrpfnl = array_unique($allwdusersgrpmlt);
1125
+            
1126
+            $allusr = array_merge($allwdusersfnl, $allwdusersgrpfnl);
1127
+            $allusruniquest = array_unique($allusr);
1128
+
1129
+            if ($allusruniquest) {
1130
+                array_unshift($allusruniquest, $userId);
1131
+                $allusruniquegr = $allusruniquest;
1132
+            } else { $allusruniquegr = [$userId]; }
1133
+
1134
+            $allusruniquegrsec = "'" . implode("','", $allusruniquegr) . "'";
1135
+        }
1136
+
1137
+        // Get received messages
1138
+
1139
+        // If the user is an admin and he wants to see his messages and the messages of all the users with whom he shares his API keys
1140
+        if ($crsampref == 1 && $this->groupManager->isAdmin($userId)) {
1141
+
1142
+            $getrecmsgsres = $this->connection->executeQuery("
1143
+			SELECT `id`, `user_id`, `date`, `from`, `to`, `message`, `author_displayname`
1144
+			FROM `*PREFIX*sms_relent_received` WHERE `user_id` IN (" . $allusruniquegrsec . ")");
1145
+
1146
+        // If the user is an admin and he wants to see only his messages
1147
+        } elseif ($crsampref == 0 && $this->groupManager->isAdmin($userId)) {
1148
+
1149
+            $getrecmsgs = $this->connection->prepare('
1150
+			SELECT `id`, `user_id`, `date`, `from`, `to`, `message`, `author_displayname`
1151
+			FROM `*PREFIX*sms_relent_received` WHERE `user_id` = ?');
1152
+	    $getrecmsgsres = $getrecmsgs->execute([$userId]);
1153
+
1154
+        // If the user is not an admin 
1155
+        } elseif (!$this->groupManager->isAdmin($userId)) {
1156
+
1157
+	    // Get the Display Name of the current user
1158
+	    $getacdatadn = $this->connection->prepare('SELECT `uid`, `name`, `value` FROM `*PREFIX*accounts_data` WHERE `uid` = ? AND `name` = ?');
1159
+	    $getacdatadnres = $getacdatadn->execute([$userId, 'displayname']);
1160
+	    $acdatausrdnadm = $getacdatadnres->fetch();
1161
+	    $cruserdname = $acdatausrdnadm['value'];
1162
+	    $getacdatadnres->closeCursor();
1163
+
1164
+            // Get the groups to which the current user belongs
1165
+            $getusrgrp = $this->connection->prepare('
1166
+	          SELECT `gid`, `uid`
1167
+	          FROM  `*PREFIX*group_user`
1168
+                  WHERE `uid` = ?');
1169
+            $getusrgrpres = $getusrgrp->execute([$userId]);
1170
+
1171
+            $usergrps = [];
1172
+            while ($fetchedgrps = $getusrgrpres->fetch()) {
1173
+                   $usergrps[] = $fetchedgrps['gid'];
1174
+            }
1175
+            $getusrgrpres->closeCursor();
1176
+
1177
+            // Get the restrictions from the 'sms_relent_restrict' table
1178
+            $getrestr = $this->connection->prepare('
1179
+		       SELECT `phone_number`, `groups`, `users`
1180
+		       FROM  `*PREFIX*sms_relent_restrict`');
1181
+            $getrestrres = $getrestr->execute();
1182
+
1183
+            $restrdata = [];
1184
+            while ($restrfetched = $getrestrres->fetch()) {
1185
+                   $restrdata[] = $restrfetched;
1186
+            }
1187
+            $getrestrres->closeCursor();
1188
+
1189
+            // Get the phone numbers that the user is allowed/not allowed to use
1190
+            if ($restrdata) {
1191
+
1192
+                $restrPhoneNmbrs = [];
1193
+                $allowedPhoneNmbrs = [];
1194
+                foreach ($restrdata as $rskey => $rsvalue) {
1195
+
1196
+                         $chck = 0;
1197
+                         $restrgrparr = explode("|", $rsvalue['groups']);
1198
+                         foreach ($restrgrparr as $rkey => $rvalue) {
1199
+                                  if ($rvalue) {
1200
+                                      if (strpos(implode("|", $usergrps), $rvalue) !== false) { $chck++; }
1201
+                                  }
1202
+                         }
1203
+                         if (strpos($rsvalue['users'], $cruserdname) !== false) { $chck++; }
1204
+
1205
+                         if ($chck == 0) { 
1206
+                             $restrPhoneNmbrs[] = $rsvalue['phone_number']; 
1207
+                         }
1208
+                }
1209
+
1210
+		$allowedPhNmbrs = $this->getsmsnumbers($userId);
1211
+
1212
+		foreach ($allowedPhNmbrs as $apnkey => $apnvalue) {
1213
+			 $crphnmbr = explode(": ", $apnvalue);
1214
+			 if ($crphnmbr[0] == 'Tx') {
1215
+			     $allowedPhoneNmbrs[] = 'Telnyx: ' . $crphnmbr[1];
1216
+			 } elseif ($crphnmbr[0] == 'Pl') {
1217
+			     $allowedPhoneNmbrs[] = 'Plivo: ' . $crphnmbr[1];
1218
+			 } elseif ($crphnmbr[0] == 'Tw') {
1219
+			     $allowedPhoneNmbrs[] = 'Twilio: ' . $crphnmbr[1];
1220
+			 } elseif ($crphnmbr[0] == 'Fl') {
1221
+			     $allowedPhoneNmbrs[] = 'Flowroute: ' . $crphnmbr[1];
1222
+			 }
1223
+		}
1224
+
1225
+                $procalwduid = $allowedPhoneNmbrs;
1226
+                $procalwduidsec = "'" . implode("','", $procalwduid) . "'";
1227
+
1228
+                if ($procalwduidsec != "''") {
1229
+
1230
+                    $getrecmsgsres = $this->connection->executeQuery("
1231
+			SELECT `id`, `user_id`, `date`, `from`, `to`, `message`, `author_displayname`
1232
+			FROM `*PREFIX*sms_relent_received`
1233
+			WHERE `user_id` = '$userId' OR `to` IN (" . $procalwduidsec . ")");
1234
+
1235
+                } else {
1236
+	            $getrectable = $this->connection->prepare('
1237
+			SELECT `id`, `user_id`, `date`, `from`, `to`, `message`, `author_displayname`
1238
+			FROM `*PREFIX*sms_relent_received`
1239
+			WHERE `user_id` = ?');
1240
+	            $getrecmsgsres = $getrectable->execute([$userId]);
1241
+                }
1242
+
1243
+            } else {
1244
+
1245
+		$allowedPhNmbrs = $this->getsmsnumbers($userId);
1246
+
1247
+		foreach ($allowedPhNmbrs as $apnkey => $apnvalue) {
1248
+			 $crphnmbr = explode(": ", $apnvalue);
1249
+			 if ($crphnmbr[0] == 'Tx') {
1250
+			     $allowedPhoneNmbrs[] = 'Telnyx: ' . $crphnmbr[1];
1251
+			 } elseif ($crphnmbr[0] == 'Pl') {
1252
+			     $allowedPhoneNmbrs[] = 'Plivo: ' . $crphnmbr[1];
1253
+			 } elseif ($crphnmbr[0] == 'Tw') {
1254
+			     $allowedPhoneNmbrs[] = 'Twilio: ' . $crphnmbr[1];
1255
+			 } elseif ($crphnmbr[0] == 'Fl') {
1256
+			     $allowedPhoneNmbrs[] = 'Flowroute: ' . $crphnmbr[1];
1257
+			 }
1258
+		}
1259
+
1260
+                $procalwduid = $allowedPhoneNmbrs;
1261
+                $procalwduidsec = "'" . implode("','", $procalwduid) . "'";
1262
+
1263
+                if ($procalwduidsec != "''") {
1264
+
1265
+                    $getrecmsgsres = $this->connection->executeQuery("
1266
+			SELECT `id`, `user_id`, `date`, `from`, `to`, `message`, `author_displayname`
1267
+			FROM `*PREFIX*sms_relent_received`
1268
+			WHERE `user_id` = '$userId' OR `to` IN (" . $procalwduidsec . ")");
1269
+
1270
+                } else {
1271
+	            $getrectable = $this->connection->prepare('
1272
+			SELECT `id`, `user_id`, `date`, `from`, `to`, `message`, `author_displayname`
1273
+			FROM `*PREFIX*sms_relent_received`
1274
+			WHERE `user_id` = ?');
1275
+	            $getrecmsgsres = $getrectable->execute([$userId]);
1276
+                }
1277
+            }
1278
+        }
1279
+
1280
+        $recmsgs = [];
1281
+        while ($rcrowsfetch = $getrecmsgsres->fetch()) {
1282
+               $rcrowsfetch['deliveryreceipt'] = '';
1283
+               $rcrowsfetch['table'] = 'received';
1284
+               $recmsgs[] = $rcrowsfetch;
1285
+        }
1286
+	$getrecmsgsres->closeCursor();
1287
+
1288
+
1289
+        // Get sent messages
1290
+
1291
+        // If the user is an admin and he wants to see his messages and the messages of all the users with whom he shares his API keys
1292
+        if ($crsampref == 1 && $this->groupManager->isAdmin($userId)) {
1293
+
1294
+            $getsentmsgsres = $this->connection->executeQuery("
1295
+		       SELECT `id`, `user_id`, `date`, `from`, `to`,`message`, `author_displayname`, `deliveryreceipt`
1296
+		       FROM  `*PREFIX*sms_relent_sent` 
1297
+                       WHERE `user_id` IN (" . $allusruniquegrsec . ")");
1298
+
1299
+        // If the user is an admin and he wants to see only his messages
1300
+        } elseif ($crsampref == 0 && $this->groupManager->isAdmin($userId)) {
1301
+
1302
+            $getsentmsgs = $this->connection->prepare('
1303
+		       SELECT `id`, `user_id`, `date`, `from`, `to`,`message`, `author_displayname`, `deliveryreceipt`
1304
+		       FROM  `*PREFIX*sms_relent_sent`
1305
+		       WHERE `user_id` = ?');
1306
+            $getsentmsgsres = $getsentmsgs->execute([$userId]);
1307
+
1308
+        // If the user is not an admin 
1309
+        } elseif (!$this->groupManager->isAdmin($userId)) {
1310
+
1311
+            if ($restrdata) {
1312
+                if ($procalwduidsec != "''") {
1313
+
1314
+	            $getsentmsgsres = $this->connection->executeQuery("
1315
+		        SELECT `id`, `user_id`, `date`, `from`, `to`,`message`, `author_displayname`, `deliveryreceipt`
1316
+		        FROM  `*PREFIX*sms_relent_sent`
1317
+			WHERE `user_id` = '$userId' OR `from` IN (" . $procalwduidsec . ")");
1318
+
1319
+                } else {
1320
+                    $getsentmsgs = $this->connection->prepare('
1321
+		        SELECT `id`, `user_id`, `date`, `from`, `to`,`message`, `author_displayname`, `deliveryreceipt`
1322
+		        FROM  `*PREFIX*sms_relent_sent`
1323
+			WHERE `user_id` = ?');
1324
+	            $getsentmsgsres = $getsentmsgs->execute([$userId]);
1325
+                }
1326
+
1327
+            } else {
1328
+
1329
+                $getsentmsgs = $this->connection->prepare('
1330
+		       SELECT `id`, `user_id`, `date`, `from`, `to`,`message`, `author_displayname`, `deliveryreceipt`
1331
+		       FROM  `*PREFIX*sms_relent_sent`
1332
+		       WHERE `user_id` = ?');
1333
+                $getsentmsgsres = $getsentmsgs->execute([$userId]);
1334
+            }
1335
+        }
1336
+
1337
+
1338
+        $sentmsgs = [];
1339
+        while ($rowfetchedsmsg = $getsentmsgsres->fetch()) {
1340
+               $rowfetchedsmsg['table'] = 'sent';
1341
+               $sentmsgs[] = $rowfetchedsmsg;
1342
+        }
1343
+        $getsentmsgsres->closeCursor();
1344
+
1345
+        $groupedfromdb = array_merge($recmsgs, $sentmsgs);
1346
+
1347
+        if ($this->groupManager->isAdmin($userId)) {
1348
+
1349
+            return $groupedfromdb;
1350
+
1351
+        } else {
1352
+
1353
+            if ($restrdata) {
1354
+
1355
+                // Clean the phone numbers from tags
1356
+                $restrPhfin = [];
1357
+                foreach ($restrPhoneNmbrs as $phkey => $phvalue) {
1358
+
1359
+                    $restrpharr = explode(": ", $phvalue);
1360
+                    $restrPhfin[] = $restrpharr[1];
1361
+                }
1362
+
1363
+                // Assemble the array of message rows that excludes the rows for the restricted phone numbers
1364
+                foreach ($groupedfromdb as $gmdkey => $gmdvalue) {
1365
+
1366
+                         if ($gmdvalue['table'] == 'sent') {
1367
+
1368
+                             if (str_contains($gmdvalue['from'], "+")) {
1369
+                                 $fromnmbrarr = explode("+", $gmdvalue['from']);
1370
+                                 if (in_array("+" . $fromnmbrarr[1], $restrPhfin)) {
1371
+                                     unset($groupedfromdb[$gmdkey]);
1372
+                                 }
1373
+                             } else {
1374
+                                 $frmnmbrarr = explode(": ", $gmdvalue['from']);
1375
+                                 if (count($frmnmbrarr) == 2) {
1376
+                                     $nmbtbcmprd = $frmnmbrarr[1];
1377
+                                 } else { 
1378
+                                     $nmbtbcmprd = $frmnmbrarr[0];
1379
+                                 }
1380
+                                 if (in_array($nmbtbcmprd, $restrPhfin)) {
1381
+                                     unset($groupedfromdb[$gmdkey]);
1382
+                                 }
1383
+                             }
1384
+
1385
+                         } elseif ($gmdvalue['table'] == 'received') {
1386
+
1387
+                             if (str_contains($gmdvalue['to'], "+")) {
1388
+                                 $fromnmbrarr = explode("+", $gmdvalue['to']);
1389
+                                 if (in_array("+" . $fromnmbrarr[1], $restrPhfin)) {
1390
+                                     unset($groupedfromdb[$gmdkey]);
1391
+                                 }
1392
+                             } else {
1393
+                                 $tonmbrarr = explode(": ", $gmdvalue['to']);
1394
+                                 if (count($tonmbrarr) == 2) {
1395
+                                     $tonmbrtbcmprd = $tonmbrarr[1];
1396
+                                 } else {
1397
+                                     $tonmbrtbcmprd = $tonmbrarr[0];
1398
+                                 }
1399
+                                 if (in_array($tonmbrtbcmprd, $restrPhfin)) {
1400
+                                     unset($groupedfromdb[$gmdkey]);
1401
+                                 }
1402
+                             }
1403
+                         }
1404
+
1405
+                }
1406
+
1407
+                $groupedfdbproc = array_values($groupedfromdb);
1408
+
1409
+                return $groupedfdbproc;
1410
+
1411
+            } else { return $groupedfromdb; }
1412
+        }
1413
+     }
1414
+
1415
+
1416
+     /**
1417
+      * @NoAdminRequired
1418
+      */
1419
+     public function getgroupedpernumber($userId, $phoneNumber) {
1420
+
1421
+        $phoneNumberpr = "%" . $phoneNumber;
1422
+
1423
+        // Get the user's preferences from the settings
1424
+        $getpref = $this->connection->prepare('
1425
+		       SELECT `user_id`, `show_all_messages`
1426
+		       FROM  `*PREFIX*sms_relent_settings` WHERE `user_id` = ?');
1427
+        $getprefres = $getpref->execute([$userId]);
1428
+        $getprefresdata = $getprefres->fetch();
1429
+        $crsampref = $getprefresdata['show_all_messages'];
1430
+        $getprefres->closeCursor();
1431
+
1432
+
1433
+        // Collect the users with whom the current admin is sharing his API keys and whose messages he will be able to see
1434
+        if ($crsampref == 1 && $this->groupManager->isAdmin($userId)) {
1435
+
1436
+            // Get the groups and users that were allowed access to the API keys
1437
+            $getgrps = $this->connection->prepare('SELECT `user_id`, `tnx_groups_allowed`, `tnx_users_allowed`, `plv_groups_allowed`, `plv_users_allowed`,
1438
+                                                  `twl_groups_allowed`, `twl_users_allowed`, `flr_groups_allowed`, `flr_users_allowed` FROM `*PREFIX*sms_relent_subac`
1439
+                                                   WHERE `user_id` = ?');
1440
+            $getgrpsres = $getgrps->execute([$userId]);
1441
+            $getgrpsusr = $getgrpsres->fetch();
1442
+            $getgrpsres->closeCursor();
1443
+
1444
+            if ($getgrpsusr) {
1445
+
1446
+                if ($getgrpsusr['tnx_users_allowed']) { $tnxusers = explode("|", $getgrpsusr['tnx_users_allowed']); } else { $tnxusers = []; }
1447
+                if ($getgrpsusr['plv_users_allowed']) { $plvusers = explode("|", $getgrpsusr['plv_users_allowed']); } else { $plvusers = []; }
1448
+                if ($getgrpsusr['twl_users_allowed']) { $twlusers = explode("|", $getgrpsusr['twl_users_allowed']); } else { $twlusers = []; }
1449
+                if ($getgrpsusr['flr_users_allowed']) { $flrusers = explode("|", $getgrpsusr['flr_users_allowed']); } else { $flrusers = []; }
1450
+
1451
+                $allwdusersarr = array_merge($tnxusers, $plvusers, $twlusers, $flrusers);
1452
+                $allwdusersunq = array_filter(array_unique($allwdusersarr));
1453
+
1454
+                if ($getgrpsusr['tnx_groups_allowed']) { $tnxgroups = explode("|", $getgrpsusr['tnx_groups_allowed']); } else { $tnxgroups = []; }
1455
+                if ($getgrpsusr['plv_groups_allowed']) { $plvgroups = explode("|", $getgrpsusr['plv_groups_allowed']); } else { $plvgroups = []; }
1456
+                if ($getgrpsusr['twl_groups_allowed']) { $twlgroups = explode("|", $getgrpsusr['twl_groups_allowed']); } else { $twlgroups = []; }
1457
+                if ($getgrpsusr['flr_groups_allowed']) { $flrgroups = explode("|", $getgrpsusr['flr_groups_allowed']); } else { $flrgroups = []; }
1458
+
1459
+                $allwdgroupsarr = array_merge($tnxgroups, $plvgroups, $twlgroups, $flrgroups);
1460
+                $allwdgroupsunq = array_filter(array_unique($allwdgroupsarr));
1461
+
1462
+            } else {
1463
+                $allwdusersunq = [];
1464
+                $allwdgroupsunq = [];
1465
+            }
1466
+
1467
+            // Get the username for each Display Name of the allowed users
1468
+            $allwdusersfnl = [];
1469
+            foreach ($allwdusersunq as $alwdusrkey => $alwdusrvalue) {
1470
+
1471
+                         $getacdatausrnm = $this->connection->prepare('SELECT `uid`, `name`, `value` FROM `*PREFIX*accounts_data` WHERE `name` = ? AND `value` = ?');
1472
+		         $getacdatausrnmres = $getacdatausrnm->execute(['displayname', $alwdusrvalue]);
1473
+		         $acdatausrname = $getacdatausrnmres->fetch();
1474
+                         if ($acdatausrname) {
1475
+                             $allwdusersfnl[] = $acdatausrname['uid'];
1476
+                         }
1477
+                         $getacdatausrnmres->closeCursor();
1478
+            }
1479
+
1480
+            // Get the users from all the allowed groups
1481
+            $allwdusersgrpmlt = [];
1482
+            foreach ($allwdgroupsunq as $prgrpkey => $prgrpvalue) {
1483
+
1484
+                     // Get all the users that belong to the current group, if the current group is different from 'admin'
1485
+                     if ($prgrpvalue != 'admin') {
1486
+                         $getusringroup = $this->connection->prepare('SELECT `gid`, `uid` FROM `*PREFIX*group_user` WHERE `gid` = ?');
1487
+		         $getusringroupres = $getusringroup->execute([$prgrpvalue]);
1488
+
1489
+		         while ($getusrname = $getusringroupres->fetch()) {
1490
+
1491
+                                $allwdusersgrpmlt[] = $getusrname['uid'];
1492
+                         }
1493
+		         $getusringroupres->closeCursor();
1494
+                     }
1495
+            }
1496
+            $allwdusersgrpfnl = array_unique($allwdusersgrpmlt);
1497
+            
1498
+            $allusr = array_merge($allwdusersfnl, $allwdusersgrpfnl);
1499
+            $allusruniquest = array_unique($allusr);
1500
+
1501
+            if ($allusruniquest) {
1502
+                array_unshift($allusruniquest, $userId);
1503
+                $allusruniquepn = $allusruniquest;
1504
+            } else { $allusruniquepn = [$userId]; }
1505
+
1506
+            $allusruniquepnst = $allusruniquepn;
1507
+
1508
+            $procardatapn = "'" . implode("','", $allusruniquepn) . "'";
1509
+
1510
+            array_unshift($allusruniquepn, $phoneNumber, $phoneNumberpr);
1511
+            $allusruniquead = $allusruniquepn;
1512
+
1513
+            array_unshift($allusruniquepnst, $phoneNumberpr, $phoneNumber);
1514
+            $allusruniqueadst = $allusruniquepnst;
1515
+        }
1516
+
1517
+
1518
+        // Get received messages
1519
+
1520
+        // If the user is an admin and he wants to see his messages and the messages of all the users with whom he shares his API keys
1521
+        if ($crsampref == 1 && $this->groupManager->isAdmin($userId)) {
1522
+
1523
+	    $getrecmsgsres = $this->connection->executeQuery("
1524
+			SELECT `id`, `user_id`, `date`, `from`, `to`, `message`, `author_displayname`
1525
+			FROM `*PREFIX*sms_relent_received` 
1526
+                        WHERE (`from` = '$phoneNumber' OR `to` LIKE '$phoneNumberpr') AND `user_id` IN (" . $procardatapn . ")");
1527
+
1528
+        // If the user is an admin and he wants to see only his messages
1529
+        } elseif ($crsampref == 0 && $this->groupManager->isAdmin($userId)) {
1530
+
1531
+            $getrecmsgs = $this->connection->prepare('
1532
+			SELECT `id`, `user_id`, `date`, `from`, `to`, `message`, `author_displayname`
1533
+			FROM `*PREFIX*sms_relent_received` 
1534
+                        WHERE `user_id` = ? AND (`from` = ? OR `to` LIKE ?)');
1535
+	    $getrecmsgsres = $getrecmsgs->execute([$userId, $phoneNumber, $phoneNumberpr]);
1536
+
1537
+        // If the user is not an admin 
1538
+        } elseif (!$this->groupManager->isAdmin($userId)) {
1539
+
1540
+	    // Get the Display Name of the current user
1541
+	    $getacdatadn = $this->connection->prepare('SELECT `uid`, `name`, `value` FROM `*PREFIX*accounts_data` WHERE `uid` = ? AND `name` = ?');
1542
+	    $getacdatadnres = $getacdatadn->execute([$userId, 'displayname']);
1543
+	    $acdatausrdnadm = $getacdatadnres->fetch();
1544
+	    $cruserdname = $acdatausrdnadm['value'];
1545
+	    $getacdatadnres->closeCursor();
1546
+
1547
+            // Get the groups to which the current user belongs
1548
+            $getusrgrp = $this->connection->prepare('
1549
+	          SELECT `gid`, `uid`
1550
+	          FROM  `*PREFIX*group_user`
1551
+                  WHERE `uid` = ?');
1552
+            $getusrgrpres = $getusrgrp->execute([$userId]);
1553
+
1554
+            $usergrps = [];
1555
+            while ($fetchedgrps = $getusrgrpres->fetch()) {
1556
+                   $usergrps[] = $fetchedgrps['gid'];
1557
+            }
1558
+            $getusrgrpres->closeCursor();
1559
+
1560
+            // Get the restrictions from the 'sms_relent_restrict' table
1561
+            $getrestr = $this->connection->prepare('
1562
+		       SELECT `phone_number`, `groups`, `users`
1563
+		       FROM  `*PREFIX*sms_relent_restrict`');
1564
+            $getrestrres = $getrestr->execute();
1565
+
1566
+            $restrdata = [];
1567
+            while ($restrfetched = $getrestrres->fetch()) {
1568
+                   $restrdata[] = $restrfetched;
1569
+            }
1570
+            $getrestrres->closeCursor();
1571
+
1572
+            // Get the phone numbers that the user is allowed/not allowed to use
1573
+            if ($restrdata) {
1574
+
1575
+                $restrPhoneNmbrs = [];
1576
+                $allowedPhoneNmbrs = [];
1577
+                foreach ($restrdata as $rskey => $rsvalue) {
1578
+
1579
+                         $chck = 0;
1580
+                         $restrgrparr = explode("|", $rsvalue['groups']);
1581
+                         foreach ($restrgrparr as $rkey => $rvalue) {
1582
+                                  if ($rvalue) {
1583
+                                      if (strpos(implode("|", $usergrps), $rvalue) !== false) { $chck++; }
1584
+                                  }
1585
+                         }
1586
+                         if (strpos($rsvalue['users'], $cruserdname) !== false) { $chck++; }
1587
+
1588
+                         if ($chck == 0) { 
1589
+                             $restrPhoneNmbrs[] = $rsvalue['phone_number']; 
1590
+                         }
1591
+                }
1592
+
1593
+		$allowedPhNmbrs = $this->getsmsnumbers($userId);
1594
+
1595
+		foreach ($allowedPhNmbrs as $apnkey => $apnvalue) {
1596
+			 $crphnmbr = explode(": ", $apnvalue);
1597
+			 if ($crphnmbr[0] == 'Tx') {
1598
+			     $allowedPhoneNmbrs[] = 'Telnyx: ' . $crphnmbr[1];
1599
+			 } elseif ($crphnmbr[0] == 'Pl') {
1600
+			     $allowedPhoneNmbrs[] = 'Plivo: ' . $crphnmbr[1];
1601
+			 } elseif ($crphnmbr[0] == 'Tw') {
1602
+			     $allowedPhoneNmbrs[] = 'Twilio: ' . $crphnmbr[1];
1603
+			 } elseif ($crphnmbr[0] == 'Fl') {
1604
+			     $allowedPhoneNmbrs[] = 'Flowroute: ' . $crphnmbr[1];
1605
+			 }
1606
+		}
1607
+
1608
+                $allowedPhoneNmbrscp = $allowedPhoneNmbrs;
1609
+
1610
+                $procalwdphnmbrs = "'" . implode("','", $allowedPhoneNmbrs) . "'";
1611
+
1612
+                if ($procalwdphnmbrs != "''") {
1613
+
1614
+	            $getrecmsgsres = $this->connection->executeQuery("
1615
+			SELECT `id`, `user_id`, `date`, `from`, `to`, `message`, `author_displayname`
1616
+			FROM `*PREFIX*sms_relent_received`
1617
+			WHERE (`user_id` = '$userId' OR `to` IN (" . $procalwdphnmbrs . ")) AND (`from` = '$phoneNumber' OR `to` LIKE '$phoneNumberpr')");
1618
+
1619
+                } else {
1620
+	            $getrecmsgs = $this->connection->prepare('
1621
+			SELECT `id`, `user_id`, `date`, `from`, `to`, `message`, `author_displayname`
1622
+			FROM `*PREFIX*sms_relent_received`
1623
+			WHERE `user_id` = ? AND (`from` = ? OR `to` LIKE ?)');
1624
+	            $getrecmsgsres = $getrecmsgs->execute([$userId, $phoneNumber, $phoneNumberpr]);
1625
+                }
1626
+
1627
+            } else {
1628
+
1629
+		$allowedPhNmbrs = $this->getsmsnumbers($userId);
1630
+
1631
+		foreach ($allowedPhNmbrs as $apnkey => $apnvalue) {
1632
+			 $crphnmbr = explode(": ", $apnvalue);
1633
+			 if ($crphnmbr[0] == 'Tx') {
1634
+			     $allowedPhoneNmbrs[] = 'Telnyx: ' . $crphnmbr[1];
1635
+			 } elseif ($crphnmbr[0] == 'Pl') {
1636
+			     $allowedPhoneNmbrs[] = 'Plivo: ' . $crphnmbr[1];
1637
+			 } elseif ($crphnmbr[0] == 'Tw') {
1638
+			     $allowedPhoneNmbrs[] = 'Twilio: ' . $crphnmbr[1];
1639
+			 } elseif ($crphnmbr[0] == 'Fl') {
1640
+			     $allowedPhoneNmbrs[] = 'Flowroute: ' . $crphnmbr[1];
1641
+			 }
1642
+		}
1643
+
1644
+                $allowedPhoneNmbrscp = $allowedPhoneNmbrs;
1645
+
1646
+                $procalwdphnmbrs = "'" . implode("','", $allowedPhoneNmbrs) . "'";
1647
+
1648
+                if ($procalwdphnmbrs != "''") {
1649
+
1650
+	            $getrecmsgsres = $this->connection->executeQuery("
1651
+			SELECT `id`, `user_id`, `date`, `from`, `to`, `message`, `author_displayname`
1652
+			FROM `*PREFIX*sms_relent_received`
1653
+			WHERE (`user_id` = '$userId' OR `to` IN (" . $procalwdphnmbrs . ")) AND (`from` = '$phoneNumber' OR `to` LIKE '$phoneNumberpr')");
1654
+
1655
+                } else {
1656
+	            $getrecmsgs = $this->connection->prepare('
1657
+			SELECT `id`, `user_id`, `date`, `from`, `to`, `message`, `author_displayname`
1658
+			FROM `*PREFIX*sms_relent_received`
1659
+			WHERE `user_id` = ? AND (`from` = ? OR `to` LIKE ?)');
1660
+	            $getrecmsgsres = $getrecmsgs->execute([$userId, $phoneNumber, $phoneNumberpr]);
1661
+                }
1662
+            }
1663
+        }
1664
+
1665
+
1666
+        $recmsgs = [];
1667
+        while ($rcrowsfetch = $getrecmsgsres->fetch()) {
1668
+               $rcrowsfetch['deliveryreceipt'] = '';
1669
+               $rcrowsfetch['table'] = 'received';
1670
+               $recmsgs[] = $rcrowsfetch;
1671
+        }
1672
+	$getrecmsgsres->closeCursor();
1673
+
1674
+
1675
+        // Get sent messages
1676
+
1677
+        // If the user is an admin and he wants to see his messages and the messages of all the users with whom he shares his API keys
1678
+        if ($crsampref == 1 && $this->groupManager->isAdmin($userId)) {
1679
+
1680
+            $getsentmsgsres = $this->connection->executeQuery("
1681
+		       SELECT `id`, `user_id`, `date`, `from`, `to`,`message`, `author_displayname`, `deliveryreceipt`
1682
+		       FROM  `*PREFIX*sms_relent_sent` 
1683
+                       WHERE (`from` LIKE '$phoneNumberpr' OR `to` = '$phoneNumber') AND `user_id` IN (" . $procardatapn . ")");
1684
+
1685
+        // If the user is an admin and he wants to see only his messages
1686
+        } elseif ($crsampref == 0 && $this->groupManager->isAdmin($userId)) {
1687
+
1688
+            $getsentmsgs = $this->connection->prepare('
1689
+		       SELECT `id`, `user_id`, `date`, `from`, `to`,`message`, `author_displayname`, `deliveryreceipt`
1690
+		       FROM  `*PREFIX*sms_relent_sent`
1691
+		       WHERE `user_id` = ? AND (`from` LIKE ? OR `to` = ?)');
1692
+            $getsentmsgsres = $getsentmsgs->execute([$userId, $phoneNumberpr, $phoneNumber]);
1693
+
1694
+
1695
+        // If the user is not an admin 
1696
+        } elseif (!$this->groupManager->isAdmin($userId)) {
1697
+
1698
+            if ($restrdata) {
1699
+                if ($procalwdphnmbrs != "''") {
1700
+
1701
+                    $getsentmsgsres = $this->connection->executeQuery("
1702
+		        SELECT `id`, `user_id`, `date`, `from`, `to`,`message`, `author_displayname`, `deliveryreceipt`
1703
+		        FROM  `*PREFIX*sms_relent_sent`
1704
+			WHERE (`user_id` = '$userId' OR `from` IN (" . $procalwdphnmbrs . ")) AND (`from` LIKE '$phoneNumberpr' OR `to` = '$phoneNumber')");
1705
+
1706
+                } else {
1707
+                    $getsentmsgs = $this->connection->prepare('
1708
+		        SELECT `id`, `user_id`, `date`, `from`, `to`,`message`, `author_displayname`, `deliveryreceipt`
1709
+		        FROM  `*PREFIX*sms_relent_sent`
1710
+			WHERE `user_id` = ? AND (`from` LIKE ? OR `to` = ?)');
1711
+	            $getsentmsgsres = $getsentmsgs->execute([$userId, $phoneNumberpr, $phoneNumber]);
1712
+                }
1713
+
1714
+            } else {
1715
+
1716
+                $getsentmsgs = $this->connection->prepare('
1717
+		       SELECT `id`, `user_id`, `date`, `from`, `to`,`message`, `author_displayname`, `deliveryreceipt`
1718
+		       FROM  `*PREFIX*sms_relent_sent`
1719
+		       WHERE `user_id` = ? AND (`from` LIKE ? OR `to` = ?)');
1720
+                $getsentmsgsres = $getsentmsgs->execute([$userId, $phoneNumberpr, $phoneNumber]);
1721
+            }
1722
+        }
1723
+
1724
+        $sentmsgs = [];
1725
+        while ($rowfetchedsmsg = $getsentmsgsres->fetch()) {
1726
+               $rowfetchedsmsg['table'] = 'sent';
1727
+               $sentmsgs[] = $rowfetchedsmsg;
1728
+        }
1729
+        $getsentmsgsres->closeCursor();
1730
+
1731
+        $groupedpernb = array_merge($recmsgs, $sentmsgs);
1732
+
1733
+        if ($this->groupManager->isAdmin($userId)) {
1734
+
1735
+            return $groupedpernb;
1736
+
1737
+        } else {
1738
+
1739
+            if ($restrdata) {
1740
+
1741
+                // Clean the phone numbers from tags
1742
+                $restrPhfin = [];
1743
+                foreach ($restrPhoneNmbrs as $phkey => $phvalue) {
1744
+
1745
+                    $restrpharr = explode(": ", $phvalue);
1746
+                    $restrPhfin[] = $restrpharr[1];
1747
+                }
1748
+
1749
+                // Assemble the array of message rows that excludes the rows for the restricted phone numbers
1750
+                foreach ($groupedpernb as $gmdkey => $gmdvalue) {
1751
+
1752
+                         if ($gmdvalue['table'] == 'sent') {
1753
+
1754
+                             if (str_contains($gmdvalue['from'], "+")) {
1755
+                                 $fromnmbrarr = explode("+", $gmdvalue['from']);
1756
+                                 if (in_array("+" . $fromnmbrarr[1], $restrPhfin)) {
1757
+                                     unset($groupedpernb[$gmdkey]);
1758
+                                 }
1759
+                             } else {
1760
+                                 $frmnmbrarr = explode(": ", $gmdvalue['from']);
1761
+                                 if (count($frmnmbrarr) == 2) {
1762
+                                     $nmbtbcmprd = $frmnmbrarr[1];
1763
+                                 } else { 
1764
+                                     $nmbtbcmprd = $frmnmbrarr[0];
1765
+                                 }
1766
+                                 if (in_array($nmbtbcmprd, $restrPhfin)) {
1767
+                                     unset($groupedpernb[$gmdkey]);
1768
+                                 }
1769
+                             }
1770
+
1771
+                         } elseif ($gmdvalue['table'] == 'received') {
1772
+
1773
+                             if (str_contains($gmdvalue['to'], "+")) {
1774
+                                 $fromnmbrarr = explode("+", $gmdvalue['to']);
1775
+                                 if (in_array("+" . $fromnmbrarr[1], $restrPhfin)) {
1776
+                                     unset($groupedpernb[$gmdkey]);
1777
+                                 }
1778
+                             } else {
1779
+                                 $tonmbrarr = explode(": ", $gmdvalue['to']);
1780
+                                 if (count($tonmbrarr) == 2) {
1781
+                                     $tonmbrtbcmprd = $tonmbrarr[1];
1782
+                                 } else {
1783
+                                     $tonmbrtbcmprd = $tonmbrarr[0];
1784
+                                 }
1785
+                                 if (in_array($tonmbrtbcmprd, $restrPhfin)) {
1786
+                                     unset($groupedpernb[$gmdkey]);
1787
+                                 }
1788
+                             }
1789
+                         }
1790
+
1791
+                }
1792
+
1793
+                $groupedpernbprc = array_values($groupedpernb);
1794
+
1795
+                return $groupedpernbprc;
1796
+
1797
+            } else { return $groupedpernb; }
1798
+        }
1799
+     }
1800
+
1801
+
1802
+     /**
1803
+      * @NoAdminRequired
1804
+      */
1805
+     public function getgroupedforreply($userId, $phoneNmbrFrom, $phoneNmbrTo) {
1806
+
1807
+        $phoneNmbrFrompr = "%" . $phoneNmbrFrom;
1808
+        $phoneNmbrTopr = "%" . $phoneNmbrTo;
1809
+
1810
+        // Get the user's preferences from the settings
1811
+        $getpref = $this->connection->prepare('
1812
+		       SELECT `user_id`, `show_all_messages`
1813
+		       FROM  `*PREFIX*sms_relent_settings` WHERE `user_id` = ?');
1814
+        $getprefres = $getpref->execute([$userId]);
1815
+        $getprefresdata = $getprefres->fetch();
1816
+        $crsampref = $getprefresdata['show_all_messages'];
1817
+        $getprefres->closeCursor();
1818
+
1819
+
1820
+        // Collect the users with whom the current admin is sharing his API keys and whose messages he will be able to see
1821
+        if ($crsampref == 1 && $this->groupManager->isAdmin($userId)) {
1822
+
1823
+            // Get the groups and users that were allowed access to the API keys
1824
+            $getgrps = $this->connection->prepare('SELECT `user_id`, `tnx_groups_allowed`, `tnx_users_allowed`, `plv_groups_allowed`, `plv_users_allowed`,
1825
+                                                  `twl_groups_allowed`, `twl_users_allowed`, `flr_groups_allowed`, `flr_users_allowed` FROM `*PREFIX*sms_relent_subac`
1826
+                                                   WHERE `user_id` = ?');
1827
+            $getgrpsres = $getgrps->execute([$userId]);
1828
+            $getgrpsusr = $getgrpsres->fetch();
1829
+            $getgrpsres->closeCursor();
1830
+
1831
+            if ($getgrpsusr) {
1832
+
1833
+                if ($getgrpsusr['tnx_users_allowed']) { $tnxusers = explode("|", $getgrpsusr['tnx_users_allowed']); } else { $tnxusers = []; }
1834
+                if ($getgrpsusr['plv_users_allowed']) { $plvusers = explode("|", $getgrpsusr['plv_users_allowed']); } else { $plvusers = []; }
1835
+                if ($getgrpsusr['twl_users_allowed']) { $twlusers = explode("|", $getgrpsusr['twl_users_allowed']); } else { $twlusers = []; }
1836
+                if ($getgrpsusr['flr_users_allowed']) { $flrusers = explode("|", $getgrpsusr['flr_users_allowed']); } else { $flrusers = []; }
1837
+
1838
+                $allwdusersarr = array_merge($tnxusers, $plvusers, $twlusers, $flrusers);
1839
+                $allwdusersunq = array_filter(array_unique($allwdusersarr));
1840
+
1841
+                if ($getgrpsusr['tnx_groups_allowed']) { $tnxgroups = explode("|", $getgrpsusr['tnx_groups_allowed']); } else { $tnxgroups = []; }
1842
+                if ($getgrpsusr['plv_groups_allowed']) { $plvgroups = explode("|", $getgrpsusr['plv_groups_allowed']); } else { $plvgroups = []; }
1843
+                if ($getgrpsusr['twl_groups_allowed']) { $twlgroups = explode("|", $getgrpsusr['twl_groups_allowed']); } else { $twlgroups = []; }
1844
+                if ($getgrpsusr['flr_groups_allowed']) { $flrgroups = explode("|", $getgrpsusr['flr_groups_allowed']); } else { $flrgroups = []; }
1845
+
1846
+                $allwdgroupsarr = array_merge($tnxgroups, $plvgroups, $twlgroups, $flrgroups);
1847
+                $allwdgroupsunq = array_filter(array_unique($allwdgroupsarr));
1848
+
1849
+            } else {
1850
+                $allwdusersunq = [];
1851
+                $allwdgroupsunq = [];
1852
+            }
1853
+
1854
+            // Get the username for each Display Name of the allowed users
1855
+            $allwdusersfnl = [];
1856
+            foreach ($allwdusersunq as $alwdusrkey => $alwdusrvalue) {
1857
+
1858
+                         $getacdatausrnm = $this->connection->prepare('SELECT `uid`, `name`, `value` FROM `*PREFIX*accounts_data` WHERE `name` = ? AND `value` = ?');
1859
+		         $getacdatausrnmres = $getacdatausrnm->execute(['displayname', $alwdusrvalue]);
1860
+		         $acdatausrname = $getacdatausrnmres->fetch();
1861
+                         if ($acdatausrname) {
1862
+                             $allwdusersfnl[] = $acdatausrname['uid'];
1863
+                         }
1864
+                         $getacdatausrnmres->closeCursor();
1865
+            }
1866
+
1867
+            // Get the users from all the allowed groups
1868
+            $allwdusersgrpmlt = [];
1869
+            foreach ($allwdgroupsunq as $prgrpkey => $prgrpvalue) {
1870
+
1871
+                     // Get all the users that belong to the current group, if the current group is different from 'admin'
1872
+                     if ($prgrpvalue != 'admin') {
1873
+                         $getusringroup = $this->connection->prepare('SELECT `gid`, `uid` FROM `*PREFIX*group_user` WHERE `gid` = ?');
1874
+		         $getusringroupres = $getusringroup->execute([$prgrpvalue]);
1875
+
1876
+		         while ($getusrname = $getusringroupres->fetch()) {
1877
+
1878
+                                $allwdusersgrpmlt[] = $getusrname['uid'];
1879
+                         }
1880
+		         $getusringroupres->closeCursor();
1881
+                     }
1882
+            }
1883
+            $allwdusersgrpfnl = array_unique($allwdusersgrpmlt);
1884
+            
1885
+            $allusr = array_merge($allwdusersfnl, $allwdusersgrpfnl);
1886
+            $allusruniquest = array_unique($allusr);
1887
+
1888
+            if ($allusruniquest) {
1889
+                array_unshift($allusruniquest, $userId);
1890
+                $allusruniquerp = $allusruniquest;
1891
+            } else { $allusruniquerp = [$userId]; }
1892
+
1893
+            $allusruniquerpst = $allusruniquerp;
1894
+
1895
+            $procardatarp = "'" . implode("','", $allusruniquerp) . "'";
1896
+        }
1897
+
1898
+
1899
+        // Get received messages
1900
+
1901
+        // If the user is an admin and he wants to see his messages and the messages of all the users with whom he shares his API keys
1902
+        if ($crsampref == 1 && $this->groupManager->isAdmin($userId)) {
1903
+
1904
+            $getrecmsgsres = $this->connection->executeQuery("
1905
+			SELECT `id`, `user_id`, `date`, `from`, `to`, `message`, `author_displayname`
1906
+			FROM `*PREFIX*sms_relent_received` 
1907
+                        WHERE ((`from` = '$phoneNmbrFrom' AND `to` LIKE '$phoneNmbrTopr') OR (`from` = '$phoneNmbrTo' AND `to` LIKE '$phoneNmbrFrompr')) AND 
1908
+                        `user_id` IN (" . $procardatarp . ")");
1909
+
1910
+        // If the user is an admin and he wants to see only his messages
1911
+        } elseif ($crsampref == 0 && $this->groupManager->isAdmin($userId)) {
1912
+
1913
+            $getrecmsgs = $this->connection->prepare('
1914
+			SELECT `id`, `user_id`, `date`, `from`, `to`, `message`, `author_displayname`
1915
+			FROM  `*PREFIX*sms_relent_received`
1916
+			WHERE `user_id` = ? AND ((`from` = ? AND `to` LIKE ?) OR (`from` = ? AND `to` LIKE ?))');
1917
+	    $getrecmsgsres = $getrecmsgs->execute([$userId, $phoneNmbrFrom, $phoneNmbrTopr, $phoneNmbrTo, $phoneNmbrFrompr]);
1918
+
1919
+        // If the user is not an admin 
1920
+        } elseif (!$this->groupManager->isAdmin($userId)) {
1921
+
1922
+	    // Get the Display Name of the current user
1923
+	    $getacdatadn = $this->connection->prepare('SELECT `uid`, `name`, `value` FROM `*PREFIX*accounts_data` WHERE `uid` = ? AND `name` = ?');
1924
+	    $getacdatadnres = $getacdatadn->execute([$userId, 'displayname']);
1925
+	    $acdatausrdnadm = $getacdatadnres->fetch();
1926
+	    $cruserdname = $acdatausrdnadm['value'];
1927
+	    $getacdatadnres->closeCursor();
1928
+
1929
+            // Get the groups to which the current user belongs
1930
+            $getusrgrp = $this->connection->prepare('
1931
+	          SELECT `gid`, `uid`
1932
+	          FROM  `*PREFIX*group_user`
1933
+                  WHERE `uid` = ?');
1934
+            $getusrgrpres = $getusrgrp->execute([$userId]);
1935
+
1936
+            $usergrps = [];
1937
+            while ($fetchedgrps = $getusrgrpres->fetch()) {
1938
+                   $usergrps[] = $fetchedgrps['gid'];
1939
+            }
1940
+            $getusrgrpres->closeCursor();
1941
+
1942
+            // Get the restrictions from the 'sms_relent_restrict' table
1943
+            $getrestr = $this->connection->prepare('
1944
+		       SELECT `phone_number`, `groups`, `users`
1945
+		       FROM  `*PREFIX*sms_relent_restrict`');
1946
+            $getrestrres = $getrestr->execute();
1947
+
1948
+            $restrdata = [];
1949
+            while ($restrfetched = $getrestrres->fetch()) {
1950
+                   $restrdata[] = $restrfetched;
1951
+            }
1952
+            $getrestrres->closeCursor();
1953
+
1954
+            // Get the phone numbers that the user is allowed/not allowed to use
1955
+            if ($restrdata) {
1956
+
1957
+                $restrPhoneNmbrs = [];
1958
+                $allowedPhoneNmbrs = [];
1959
+                foreach ($restrdata as $rskey => $rsvalue) {
1960
+
1961
+                         $chck = 0;
1962
+                         $restrgrparr = explode("|", $rsvalue['groups']);
1963
+                         foreach ($restrgrparr as $rkey => $rvalue) {
1964
+                                  if ($rvalue) {
1965
+                                      if (strpos(implode("|", $usergrps), $rvalue) !== false) { $chck++; }
1966
+                                  }
1967
+                         }
1968
+                         if (strpos($rsvalue['users'], $cruserdname) !== false) { $chck++; }
1969
+
1970
+                         if ($chck == 0) { 
1971
+                             $restrPhoneNmbrs[] = $rsvalue['phone_number']; 
1972
+                         }
1973
+                }
1974
+
1975
+		$allowedPhNmbrs = $this->getsmsnumbers($userId);
1976
+
1977
+		foreach ($allowedPhNmbrs as $apnkey => $apnvalue) {
1978
+			 $crphnmbr = explode(": ", $apnvalue);
1979
+			 if ($crphnmbr[0] == 'Tx') {
1980
+			     $allowedPhoneNmbrs[] = 'Telnyx: ' . $crphnmbr[1];
1981
+			 } elseif ($crphnmbr[0] == 'Pl') {
1982
+			     $allowedPhoneNmbrs[] = 'Plivo: ' . $crphnmbr[1];
1983
+			 } elseif ($crphnmbr[0] == 'Tw') {
1984
+			     $allowedPhoneNmbrs[] = 'Twilio: ' . $crphnmbr[1];
1985
+			 } elseif ($crphnmbr[0] == 'Fl') {
1986
+			     $allowedPhoneNmbrs[] = 'Flowroute: ' . $crphnmbr[1];
1987
+			 }
1988
+		}
1989
+
1990
+                $allowedPhoneNmbrscpr = $allowedPhoneNmbrs;
1991
+
1992
+                $procalwdphnmbrs = "'" . implode("','", $allowedPhoneNmbrs) . "'";
1993
+
1994
+                if ($procalwdphnmbrs != "''") {
1995
+
1996
+                    $getrecmsgsres = $this->connection->executeQuery("
1997
+			SELECT `id`, `user_id`, `date`, `from`, `to`, `message`, `author_displayname`
1998
+			FROM `*PREFIX*sms_relent_received`
1999
+			WHERE (`user_id` = '$userId' OR `to` IN (" . $procalwdphnmbrs . ")) AND ((`from` = '$phoneNmbrFrom' AND `to` LIKE '$phoneNmbrTopr') OR (`from` = '$phoneNmbrTo' 
2000
+                                AND `to` LIKE '$phoneNmbrFrompr'))");
2001
+
2002
+                } else {
2003
+	            $getrecmsgs = $this->connection->prepare('
2004
+			SELECT `id`, `user_id`, `date`, `from`, `to`, `message`, `author_displayname`
2005
+			FROM `*PREFIX*sms_relent_received`
2006
+			WHERE `user_id` = ? AND ((`from` = ? AND `to` LIKE ?) OR (`from` = ? AND `to` LIKE ?))');
2007
+	            $getrecmsgsres = $getrecmsgs->execute([$userId, $phoneNmbrFrom, $phoneNmbrTopr, $phoneNmbrTo, $phoneNmbrFrompr]);
2008
+                }
2009
+
2010
+            } else {
2011
+
2012
+		$allowedPhNmbrs = $this->getsmsnumbers($userId);
2013
+
2014
+		foreach ($allowedPhNmbrs as $apnkey => $apnvalue) {
2015
+			 $crphnmbr = explode(": ", $apnvalue);
2016
+			 if ($crphnmbr[0] == 'Tx') {
2017
+			     $allowedPhoneNmbrs[] = 'Telnyx: ' . $crphnmbr[1];
2018
+			 } elseif ($crphnmbr[0] == 'Pl') {
2019
+			     $allowedPhoneNmbrs[] = 'Plivo: ' . $crphnmbr[1];
2020
+			 } elseif ($crphnmbr[0] == 'Tw') {
2021
+			     $allowedPhoneNmbrs[] = 'Twilio: ' . $crphnmbr[1];
2022
+			 } elseif ($crphnmbr[0] == 'Fl') {
2023
+			     $allowedPhoneNmbrs[] = 'Flowroute: ' . $crphnmbr[1];
2024
+			 }
2025
+		}
2026
+
2027
+                $allowedPhoneNmbrscpr = $allowedPhoneNmbrs;
2028
+
2029
+                $procalwdphnmbrs = "'" . implode("','", $allowedPhoneNmbrs) . "'";
2030
+
2031
+                if ($procalwdphnmbrs != "''") {
2032
+
2033
+                    $getrecmsgsres = $this->connection->executeQuery("
2034
+			SELECT `id`, `user_id`, `date`, `from`, `to`, `message`, `author_displayname`
2035
+			FROM `*PREFIX*sms_relent_received`
2036
+			WHERE (`user_id` = '$userId' OR `to` IN (" . $procalwdphnmbrs . ")) AND ((`from` = '$phoneNmbrFrom' AND `to` LIKE '$phoneNmbrTopr') OR (`from` = '$phoneNmbrTo' 
2037
+                                AND `to` LIKE '$phoneNmbrFrompr'))");
2038
+
2039
+                } else {
2040
+	            $getrecmsgs = $this->connection->prepare('
2041
+			SELECT `id`, `user_id`, `date`, `from`, `to`, `message`, `author_displayname`
2042
+			FROM `*PREFIX*sms_relent_received`
2043
+			WHERE `user_id` = ? AND ((`from` = ? AND `to` LIKE ?) OR (`from` = ? AND `to` LIKE ?))');
2044
+	            $getrecmsgsres = $getrecmsgs->execute([$userId, $phoneNmbrFrom, $phoneNmbrTopr, $phoneNmbrTo, $phoneNmbrFrompr]);
2045
+                }
2046
+            }
2047
+        }
2048
+
2049
+        $recmsgs = [];
2050
+        while ($rcrowsfetch = $getrecmsgsres->fetch()) {
2051
+               $rcrowsfetch['deliveryreceipt'] = '';
2052
+               $rcrowsfetch['table'] = 'received';
2053
+               $recmsgs[] = $rcrowsfetch;
2054
+        }
2055
+	$getrecmsgsres->closeCursor();
2056
+
2057
+
2058
+        // Get sent messages
2059
+
2060
+        // If the user is an admin and he wants to see his messages and the messages of all the users with whom he shares his API keys
2061
+        if ($crsampref == 1 && $this->groupManager->isAdmin($userId)) {
2062
+
2063
+            $getsentmsgsres = $this->connection->executeQuery("
2064
+		       SELECT `id`, `user_id`, `date`, `from`, `to`,`message`, `author_displayname`, `deliveryreceipt`
2065
+		       FROM  `*PREFIX*sms_relent_sent` 
2066
+                       WHERE ((`from` LIKE '$phoneNmbrFrompr' AND `to` = '$phoneNmbrTo') OR (`from` LIKE '$phoneNmbrTopr' AND `to` = '$phoneNmbrFrom')) AND `user_id` IN 
2067
+                       (" . $procardatarp . ")");
2068
+
2069
+        // If the user is an admin and he wants to see only his messages
2070
+        } elseif ($crsampref == 0 && $this->groupManager->isAdmin($userId)) {
2071
+
2072
+            $getsentmsgs = $this->connection->prepare('
2073
+		       SELECT `id`, `user_id`, `date`, `from`, `to`,`message`, `author_displayname`, `deliveryreceipt`
2074
+		       FROM `*PREFIX*sms_relent_sent`
2075
+		       WHERE `user_id` = ? AND ((`from` LIKE ? AND `to` = ?) OR (`from` LIKE ? AND `to` = ?))');
2076
+            $getsentmsgsres = $getsentmsgs->execute([$userId, $phoneNmbrFrompr, $phoneNmbrTo, $phoneNmbrTopr, $phoneNmbrFrom]);
2077
+
2078
+        // If the user is not an admin
2079
+        } elseif (!$this->groupManager->isAdmin($userId)) {
2080
+
2081
+            if ($restrdata) {
2082
+                if ($procalwdphnmbrs != "''") {
2083
+
2084
+	            $getsentmsgsres = $this->connection->executeQuery("
2085
+		       SELECT `id`, `user_id`, `date`, `from`, `to`,`message`, `author_displayname`, `deliveryreceipt`
2086
+		       FROM `*PREFIX*sms_relent_sent`
2087
+		       WHERE (`user_id` = '$userId' OR `from` IN (" . $procalwdphnmbrs . ")) AND ((`from` LIKE '$phoneNmbrFrompr' AND `to` = '$phoneNmbrTo') OR 
2088
+                       (`from` LIKE '$phoneNmbrTopr' AND `to` = '$phoneNmbrFrom'))");
2089
+
2090
+                } else {
2091
+                    $getsentmsgs = $this->connection->prepare('
2092
+		       SELECT `id`, `user_id`, `date`, `from`, `to`,`message`, `author_displayname`, `deliveryreceipt`
2093
+		       FROM `*PREFIX*sms_relent_sent`
2094
+		       WHERE `user_id` = ? AND ((`from` LIKE ? AND `to` = ?) OR (`from` LIKE ? AND `to` = ?))');
2095
+	            $getsentmsgsres = $getsentmsgs->execute([$userId, $phoneNmbrFrompr, $phoneNmbrTo, $phoneNmbrTopr, $phoneNmbrFrom]);
2096
+                }
2097
+
2098
+            } else {
2099
+
2100
+                $getsentmsgs = $this->connection->prepare('
2101
+		       SELECT `id`, `user_id`, `date`, `from`, `to`,`message`, `author_displayname`, `deliveryreceipt`
2102
+		       FROM `*PREFIX*sms_relent_sent`
2103
+		       WHERE `user_id` = ? AND ((`from` LIKE ? AND `to` = ?) OR (`from` LIKE ? AND `to` = ?))');
2104
+                $getsentmsgsres = $getsentmsgs->execute([$userId, $phoneNmbrFrompr, $phoneNmbrTo, $phoneNmbrTopr, $phoneNmbrFrom]);
2105
+            }
2106
+        }
2107
+
2108
+        $sentmsgs = [];
2109
+        while ($rowfetchedsmsg = $getsentmsgsres->fetch()) {
2110
+               $rowfetchedsmsg['table'] = 'sent';
2111
+               $sentmsgs[] = $rowfetchedsmsg;
2112
+        }
2113
+        $getsentmsgsres->closeCursor();
2114
+
2115
+        $groupedpernb = array_merge($recmsgs, $sentmsgs);
2116
+
2117
+        if ($this->groupManager->isAdmin($userId)) {
2118
+
2119
+            return $groupedpernb;
2120
+
2121
+        } else {
2122
+
2123
+            if ($restrdata) {
2124
+
2125
+                // Clean the phone numbers from tags
2126
+                $restrPhfin = [];
2127
+                foreach ($restrPhoneNmbrs as $phkey => $phvalue) {
2128
+
2129
+                    $restrpharr = explode(": ", $phvalue);
2130
+                    $restrPhfin[] = $restrpharr[1];
2131
+                }
2132
+
2133
+                // Assemble the array of message rows that excludes the rows for the restricted phone numbers
2134
+                foreach ($groupedpernb as $gmdkey => $gmdvalue) {
2135
+
2136
+                         if ($gmdvalue['table'] == 'sent') {
2137
+
2138
+                             if (str_contains($gmdvalue['from'], "+")) {
2139
+                                 $fromnmbrarr = explode("+", $gmdvalue['from']);
2140
+                                 if (in_array("+" . $fromnmbrarr[1], $restrPhfin)) {
2141
+                                     unset($groupedpernb[$gmdkey]);
2142
+                                 }
2143
+                             } else {
2144
+                                 $frmnmbrarr = explode(": ", $gmdvalue['from']);
2145
+                                 if (count($frmnmbrarr) == 2) {
2146
+                                     $nmbtbcmprd = $frmnmbrarr[1];
2147
+                                 } else { 
2148
+                                     $nmbtbcmprd = $frmnmbrarr[0];
2149
+                                 }
2150
+                                 if (in_array($nmbtbcmprd, $restrPhfin)) {
2151
+                                     unset($groupedpernb[$gmdkey]);
2152
+                                 }
2153
+                             }
2154
+
2155
+                         } elseif ($gmdvalue['table'] == 'received') {
2156
+
2157
+                             if (str_contains($gmdvalue['to'], "+")) {
2158
+                                 $fromnmbrarr = explode("+", $gmdvalue['to']);
2159
+                                 if (in_array("+" . $fromnmbrarr[1], $restrPhfin)) {
2160
+                                     unset($groupedpernb[$gmdkey]);
2161
+                                 }
2162
+                             } else {
2163
+                                 $tonmbrarr = explode(": ", $gmdvalue['to']);
2164
+                                 if (count($tonmbrarr) == 2) {
2165
+                                     $tonmbrtbcmprd = $tonmbrarr[1];
2166
+                                 } else {
2167
+                                     $tonmbrtbcmprd = $tonmbrarr[0];
2168
+                                 }
2169
+                                 if (in_array($tonmbrtbcmprd, $restrPhfin)) {
2170
+                                     unset($groupedpernb[$gmdkey]);
2171
+                                 }
2172
+                             }
2173
+                         }
2174
+
2175
+                }
2176
+
2177
+                $groupedperconv = array_values($groupedpernb);
2178
+
2179
+                return $groupedperconv;
2180
+
2181
+            } else { return $groupedpernb; }
2182
+        }
2183
+     }
2184
+
2185
+
2186
+
2187
+     /**
2188
+      * @NoAdminRequired
2189
+      */
2190
+     public function savedisplayname($userId, $authorDisplayname, $from) {
2191
+
2192
+        if ($this->groupManager->isAdmin($userId)) {
2193
+
2194
+	    $updatedispnm = $this->connection->prepare('
2195
+			UPDATE `*PREFIX*sms_relent_received`
2196
+			SET `author_displayname` = ?
2197
+                        WHERE `from` = ?');
2198
+	    $updatedispnmres = $updatedispnm->execute([$authorDisplayname, $from]);
2199
+
2200
+            if ($updatedispnmres) {
2201
+                return $respupdname = "The new Display Name has been saved. If on the Settings page, the option 'Add the display name of the message author, before each message' is checked, when you refresh the page you will see the new Display Name before the messages.";
2202
+            } else {
2203
+                return $respupdname = "Error while trying to save the new Display Name to the database.";
2204
+            }
2205
+	    $updatedispnmres->closeCursor();
2206
+
2207
+        } else { return $respupdname = "Only admins can save Display Names for phone numbers that are not associated with Nextcloud users."; }
2208
+     }
2209
+
2210
+     /**
2211
+      * @NoAdminRequired
2212
+      */
2213
+     public function getmsgsperpagenewmsg($userId) {
2214
+
2215
+        $sqlmpp = $this->connection->prepare('
2216
+	       SELECT `user_id`, `messagesperpage`, `msg_check_interval` 
2217
+               FROM `*PREFIX*sms_relent_settings`
2218
+               WHERE `user_id` = ?');
2219
+	$result = $sqlmpp->execute([$userId]);
2220
+        $mesppdata = $result->fetch();
2221
+        $result->closeCursor();
2222
+        if ($mesppdata) {
2223
+            $mesperpagedb = ['msgsperpage' => $mesppdata['messagesperpage'], 'newmsgcheck' => $mesppdata['msg_check_interval']];
2224
+            return $mesperpagedb;
2225
+        }
2226
+     }
2227
+
2228
+     /**
2229
+      * @NoAdminRequired
2230
+      */
2231
+     public function getnewmsgindicator($userId) {
2232
+
2233
+        $sqlnmsg = $this->connection->prepare('
2234
+	       SELECT `user_id`, `new_message_rcd` 
2235
+               FROM `*PREFIX*sms_relent_settings`
2236
+               WHERE `user_id` = ?');
2237
+	$resultnmsg = $sqlnmsg->execute([$userId]);
2238
+        $nmsgdata = $resultnmsg->fetch();
2239
+        $resultnmsg->closeCursor();
2240
+
2241
+        if ($nmsgdata) {
2242
+            $newmsgdb = $nmsgdata['new_message_rcd'];
2243
+
2244
+            if ($newmsgdb == 1) {
2245
+                // Change the 'new message received' indicator to 0 in the 'sms_relent_settings' table, for the current user
2246
+                $newMsgRcd = 0;
2247
+	        $sqlupdnmsc = $this->connection->prepare('
2248
+			UPDATE `*PREFIX*sms_relent_settings`
2249
+			SET `new_message_rcd` = ?
2250
+	                WHERE `user_id` = ?');
2251
+	        $updatenmRcd = $sqlupdnmsc->execute([$newMsgRcd, $userId]);
2252
+	        $updatenmRcd->closeCursor();
2253
+            }
2254
+
2255
+            return $newmsgdb;
2256
+        }
2257
+     }
2258
+
2259
+     /**
2260
+      * @NoAdminRequired
2261
+      */
2262
+     public function getsettings($userId) {
2263
+
2264
+        $getsettings = $this->connection->prepare('
2265
+                    SELECT `id`, `user_id`, `telapi_url_rec`, `telapi_url`, `nexapi_url_rec`, `nexapi_url`, `twilapi_url_rec`, `twilapi_url`, `flowapi_url_rec`, `flowapi_url`, 
2266
+                           `messagesperpage`, `get_notify`, `notification_email`, `getsmsinemail`, `show_display_names`, `add_display_names`, `msg_check_interval`                           
2267
+		    FROM  `*PREFIX*sms_relent_settings`
2268
+		    WHERE `user_id` = ?');
2269
+        $resultsettings = $getsettings->execute([$userId]);
2270
+
2271
+        $settingsfromdb = $resultsettings->fetch();
2272
+
2273
+        $resultsettings->closeCursor();
2274
+
2275
+        if ($settingsfromdb) {
2276
+
2277
+            if ($this->groupManager->isAdmin($userId)) { $adminreguser = 'admin'; } else { $adminreguser = 'reguser'; }
2278
+            $settingsfromdb['adminornot'] = $adminreguser;
2279
+
2280
+            return $settingsfromdb;
2281
+        }
2282
+
2283
+     }
2284
+
2285
+
2286
+     public function updatenumberrestrictions($userId, $savedByDsplname, $phoneNumber, $groups, $users) {
2287
+
2288
+        if ($this->groupManager->isAdmin($userId)) {
2289
+
2290
+            $groupsproc = implode("|", $groups);
2291
+            $usersproc = implode("|", $users);
2292
+
2293
+            // Get the restrictions for the current number from the 'sms_relent_restrict' table
2294
+            $getrestr = $this->connection->prepare('SELECT `user_id`, `saved_by_dsplname`, `phone_number`, `groups`, `users` FROM `*PREFIX*sms_relent_restrict` WHERE
2295
+                                                   `phone_number` = ?');
2296
+            $getrestrresult = $getrestr->execute([$phoneNumber]);
2297
+            $crntrestr = $getrestrresult->fetch();
2298
+            $getrestrresult->closeCursor();
2299
+
2300
+            if ($getrestrresult && !$crntrestr) {
2301
+
2302
+	        $insertphrestr = $this->connection->prepare('INSERT INTO `*PREFIX*sms_relent_restrict` (`user_id`, `saved_by_dsplname`, `phone_number`, `groups`, `users`) VALUES
2303
+                                                             (?, ?, ?, ?, ?)');
2304
+	        if ($insertphrestr->execute([$userId, $savedByDsplname, $phoneNumber, $groupsproc, $usersproc])) { $messagetosend = 'success'; } else { $messagetosend = 'failure'; }  
2305
+         
2306
+            } elseif ($getrestrresult && $crntrestr) {
2307
+
2308
+	        $updatephrestr = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_restrict` SET `user_id` = ?, `saved_by_dsplname` = ?, `groups` = ?, `users` = ? WHERE 
2309
+                                                            `phone_number` = ?');
2310
+	        if ($admupdatephonerestr = $updatephrestr->execute([$userId, $savedByDsplname, $groupsproc, $usersproc, $phoneNumber])) { 
2311
+                    $messagetosend = 'success';
2312
+                } else { 
2313
+                    $messagetosend = 'failure'; 
2314
+                }
2315
+
2316
+	        $admupdatephonerestr->closeCursor();
2317
+            }
2318
+            return $messagetosend;
2319
+        }
2320
+     }
2321
+
2322
+
2323
+     private function updateusercredentials($userId, $usersarr, $provider, $telapiKey, $telpubKey, $telmsgprofid, $telsendername, $plivoapikey, $plivoapisecret, $plivosendernm, 
2324
+                                            $twilapikey, $twilapisecret, $twilsendernm, $flowapikey, $flowapisecret) {
2325
+
2326
+        $msgtosend = 'success';
2327
+
2328
+        foreach ($usersarr as $usrkey => $usrvalue) {
2329
+
2330
+            $getusrset = $this->connection->prepare('SELECT `user_id` FROM `*PREFIX*sms_relent_settings` WHERE `user_id` = ?');
2331
+	    $getusrsetres = $getusrset->execute([$usrvalue]);
2332
+	    $getcrunmdata = $getusrsetres->fetch();
2333
+	    $getusrsetres->closeCursor();
2334
+
2335
+            if ($getcrunmdata) {
2336
+
2337
+                if ($provider == "tnx") {
2338
+
2339
+                    $upusrset = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_settings` SET `telapi_key` = ?, `tel_pub_key` = ?, `messaging_profile_id` = ?,
2340
+                                                           `tel_sender_name` = ? WHERE `user_id` = ?');
2341
+                    if ($upusrsetres = $upusrset->execute([$telapiKey, $telpubKey, $telmsgprofid, $telsendername, $usrvalue])) {
2342
+                        $msgtosend = 'success';
2343
+                    } else { $msgtosend = 'failure'; }
2344
+                    $upusrsetres->closeCursor();
2345
+
2346
+                } elseif ($provider == "plv") {
2347
+
2348
+                    $upusrset = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_settings` SET `nexapi_key` = ?, `nexapi_secret` = ?, `nex_sender_name` = ?
2349
+                                                            WHERE `user_id` = ?');
2350
+                    if ($upusrsetres = $upusrset->execute([$plivoapikey, $plivoapisecret, $plivosendernm, $usrvalue])) {
2351
+                        $msgtosend = 'success';
2352
+                    } else { $msgtosend = 'failure'; }
2353
+                    $upusrsetres->closeCursor();
2354
+
2355
+                } elseif ($provider == "twl") {
2356
+
2357
+                    $upusrset = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_settings` SET `twilapi_key` = ?, `twilapi_secret` = ?, `twil_sender_name` = ?
2358
+                                                            WHERE `user_id` = ?');
2359
+                    if ($upusrsetres = $upusrset->execute([$twilapikey, $twilapisecret, $twilsendernm, $usrvalue])) {
2360
+                        $msgtosend = 'success';
2361
+                    } else { $msgtosend = 'failure'; }
2362
+                    $upusrsetres->closeCursor();
2363
+
2364
+                } elseif ($provider == "flr") {
2365
+
2366
+                    $upusrset = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_settings` SET `flowapi_key` = ?, `flowapi_secret` = ? WHERE `user_id` = ?');
2367
+                    if ($upusrsetres = $upusrset->execute([$flowapikey, $flowapisecret, $usrvalue])) {
2368
+                        $msgtosend = 'success';
2369
+                    } else { $msgtosend = 'failure'; }
2370
+                    $upusrsetres->closeCursor();
2371
+                }
2372
+
2373
+            } else {
2374
+
2375
+                $emptfld = "";
2376
+
2377
+                if ($provider == "tnx") {
2378
+
2379
+                    $upusrset = $this->connection->prepare('INSERT INTO `*PREFIX*sms_relent_settings` (`user_id`, `telapi_key`, `tel_pub_key`, `telapi_url_rec`, `telapi_url`,
2380
+                                                           `messaging_profile_id`, `nexapi_key`, `nexapi_secret`, `nexapi_url_rec`, `nexapi_url`, `twilapi_key`, `twilapi_secret`,
2381
+                                                           `twilapi_url_rec`, `twilapi_url`, `flowapi_key`, `flowapi_secret`, `flowapi_url_rec`, `flowapi_url`, `tel_sender_name`) 
2382
+                                                            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
2383
+                    if ($upusrsetres = $upusrset->execute([$usrvalue, $telapiKey, $telpubKey, $emptfld, $emptfld, $telmsgprofid, $emptfld, $emptfld, $emptfld, $emptfld, $emptfld, 
2384
+                                                           $emptfld, $emptfld, $emptfld, $emptfld, $emptfld, $emptfld, $emptfld, $telsendername])) {
2385
+                        $msgtosend = 'success';
2386
+                    } else { $msgtosend = 'failure'; }
2387
+                    $upusrsetres->closeCursor();
2388
+
2389
+                } elseif ($provider == "plv") {
2390
+
2391
+                    $upusrset = $this->connection->prepare('INSERT INTO `*PREFIX*sms_relent_settings` (`user_id`, `telapi_key`, `tel_pub_key`, `telapi_url_rec`, `telapi_url`,
2392
+                                                           `messaging_profile_id`, `nexapi_key`, `nexapi_secret`, `nexapi_url_rec`, `nexapi_url`, `twilapi_key`, `twilapi_secret`,
2393
+                                                           `twilapi_url_rec`, `twilapi_url`, `flowapi_key`, `flowapi_secret`, `flowapi_url_rec`, `flowapi_url`, `nex_sender_name`)
2394
+                                                            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
2395
+                    if ($upusrsetres = $upusrset->execute([$usrvalue, $telapiKey, $telpubKey, $emptfld, $emptfld, $telmsgprofid, $plivoapikey, $plivoapisecret, $emptfld, $emptfld, 
2396
+                                                           $emptfld, $emptfld, $emptfld, $emptfld, $emptfld, $emptfld, $emptfld, $emptfld, $plivosendernm])) {
2397
+                        $msgtosend = 'success';
2398
+                    } else { $msgtosend = 'failure'; }
2399
+                    $upusrsetres->closeCursor();
2400
+
2401
+                } elseif ($provider == "twl") {
2402
+
2403
+                    $upusrset = $this->connection->prepare('INSERT INTO `*PREFIX*sms_relent_settings` (`user_id`, `telapi_key`, `tel_pub_key`, `telapi_url_rec`, `telapi_url`,
2404
+                                                           `messaging_profile_id`, `nexapi_key`, `nexapi_secret`, `nexapi_url_rec`, `nexapi_url`, `twilapi_key`, `twilapi_secret`,
2405
+                                                           `twilapi_url_rec`, `twilapi_url`, `flowapi_key`, `flowapi_secret`, `flowapi_url_rec`, `flowapi_url`, `twil_sender_name`)
2406
+                                                            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
2407
+                    if ($upusrsetres = $upusrset->execute([$usrvalue, $telapiKey, $telpubKey, $emptfld, $emptfld, $telmsgprofid, $plivoapikey, $plivoapisecret, $emptfld, $emptfld, 
2408
+                                                           $twilapikey, $twilapisecret, $emptfld, $emptfld, $emptfld, $emptfld, $emptfld, $emptfld, $twilsendernm])) {
2409
+                        $msgtosend = 'success';
2410
+                    } else { $msgtosend = 'failure'; }
2411
+                    $upusrsetres->closeCursor();
2412
+
2413
+                } elseif ($provider == "flr") {
2414
+
2415
+                    $upusrset = $this->connection->prepare('INSERT INTO `*PREFIX*sms_relent_settings` (`user_id`, `telapi_key`, `tel_pub_key`, `telapi_url_rec`, `telapi_url`,
2416
+                                                           `messaging_profile_id`, `nexapi_key`, `nexapi_secret`, `nexapi_url_rec`, `nexapi_url`, `twilapi_key`, `twilapi_secret`,
2417
+                                                           `twilapi_url_rec`, `twilapi_url`, `flowapi_key`, `flowapi_secret`, `flowapi_url_rec`, `flowapi_url`)
2418
+                                                            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
2419
+                    if ($upusrsetres = $upusrset->execute([$usrvalue, $telapiKey, $telpubKey, $emptfld, $emptfld, $telmsgprofid, $plivoapikey, $plivoapisecret, $emptfld, $emptfld, 
2420
+                                                           $twilapikey, $twilapisecret, $emptfld, $emptfld, $flowapikey, $flowapisecret, $emptfld, $emptfld])) {
2421
+                        $msgtosend = 'success';
2422
+                    } else { $msgtosend = 'failure'; }
2423
+                    $upusrsetres->closeCursor();
2424
+                }
2425
+
2426
+            }                 
2427
+        }
2428
+
2429
+        return $msgtosend;
2430
+     }
2431
+
2432
+
2433
+     private function removeusercredentials($userId, $usersarr, $provider, $telapiKey, $telpubKey, $telmsgprofid, $telsendername, $plivoapikey, $plivoapisecret, $plivosendernm, 
2434
+                                            $twilapikey, $twilapisecret, $twilsendernm, $flowapikey, $flowapisecret) {
2435
+
2436
+        $msgtosend = 'success';
2437
+
2438
+        foreach ($usersarr as $usrkey => $usrvalue) {
2439
+
2440
+                $emptyfld = "";
2441
+
2442
+                if ($provider == "tnx") {
2443
+
2444
+                    $upusrset = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_settings` SET `telapi_key` = ?, `tel_pub_key` = ?, `messaging_profile_id` = ?,
2445
+                                                           `tel_sender_name` = ? WHERE `user_id` = ?');
2446
+                    if ($upusrsetres = $upusrset->execute([$emptyfld, $emptyfld, $emptyfld, $emptyfld, $usrvalue])) {
2447
+                        $msgtosend = 'success';
2448
+                    } else { $msgtosend = 'failure'; }
2449
+                    $upusrsetres->closeCursor();
2450
+
2451
+                } elseif ($provider == "plv") {
2452
+
2453
+                    $upusrset = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_settings` SET `nexapi_key` = ?, `nexapi_secret` = ?, `nex_sender_name` = ?
2454
+                                                            WHERE `user_id` = ?');
2455
+                    if ($upusrsetres = $upusrset->execute([$emptyfld, $emptyfld, $emptyfld, $usrvalue])) {
2456
+                        $msgtosend = 'success';
2457
+                    } else { $msgtosend = 'failure'; }
2458
+                    $upusrsetres->closeCursor();
2459
+
2460
+                } elseif ($provider == "twl") {
2461
+
2462
+                    $upusrset = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_settings` SET `twilapi_key` = ?, `twilapi_secret` = ?, `twil_sender_name` = ?
2463
+                                                            WHERE `user_id` = ?');
2464
+                    if ($upusrsetres = $upusrset->execute([$emptyfld, $emptyfld, $emptyfld, $usrvalue])) {
2465
+                        $msgtosend = 'success';
2466
+                    } else { $msgtosend = 'failure'; }
2467
+                    $upusrsetres->closeCursor();
2468
+
2469
+                } elseif ($provider == "flr") {
2470
+
2471
+                    $upusrset = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_settings` SET `flowapi_key` = ?, `flowapi_secret` = ? WHERE `user_id` = ?');
2472
+                    if ($upusrsetres = $upusrset->execute([$emptyfld, $emptyfld, $usrvalue])) {
2473
+                        $msgtosend = 'success';
2474
+                    } else { $msgtosend = 'failure'; }
2475
+                    $upusrsetres->closeCursor();
2476
+                }
2477
+        }
2478
+
2479
+        return $msgtosend;
2480
+     }
2481
+
2482
+
2483
+     public function updatekeysallowedusers($userId, $groups, $users, $provider) {
2484
+
2485
+       if ($this->groupManager->isAdmin($userId)) {
2486
+
2487
+          $msgtosend = 'success';
2488
+
2489
+          // Get the users that belong to the 'admin' group
2490
+          $getadmn = $this->connection->prepare('SELECT `gid`, `uid` FROM `*PREFIX*group_user` WHERE `gid` = ?');
2491
+          $getadmnres = $getadmn->execute(['admin']);
2492
+
2493
+          $usersadmin = [];
2494
+          while ($getadmnusrs = $getadmnres->fetch()) {
2495
+                 $usersadmin[] = $getadmnusrs['uid'];
2496
+          }
2497
+          $getadmnres->closeCursor();
2498
+          
2499
+          // Get the API keys and alphanumeric sender IDs for the current admin, from the 'sms_relent_settings' table
2500
+          $getadmset = $this->connection->prepare('SELECT `user_id`, `telapi_key`, `tel_pub_key`, `messaging_profile_id`, `tel_sender_name`, `nexapi_key`, `nexapi_secret`,
2501
+                                                  `nex_sender_name`, `twilapi_key`, `twilapi_secret`, `twil_sender_name`, `flowapi_key`, `flowapi_secret` 
2502
+                                                   FROM `*PREFIX*sms_relent_settings` WHERE `user_id` = ?');
2503
+	  $getadmsetres = $getadmset->execute([$userId]);
2504
+	  $getcradmdata = $getadmsetres->fetch();
2505
+          $telapiKey = $getcradmdata['telapi_key'];
2506
+          $telpubKey = $getcradmdata['tel_pub_key'];
2507
+          $telmsgprofid = $getcradmdata['messaging_profile_id'];
2508
+          $telsendername = $getcradmdata['tel_sender_name'];
2509
+          $plivoapikey = $getcradmdata['nexapi_key'];
2510
+          $plivoapisecret = $getcradmdata['nexapi_secret'];
2511
+          $plivosendernm = $getcradmdata['nex_sender_name'];
2512
+          $twilapikey = $getcradmdata['twilapi_key'];
2513
+          $twilapisecret = $getcradmdata['twilapi_secret'];
2514
+          $twilsendernm = $getcradmdata['twil_sender_name'];
2515
+          $flowapikey = $getcradmdata['flowapi_key'];
2516
+          $flowapisecret = $getcradmdata['flowapi_secret'];
2517
+	  $getadmsetres->closeCursor();
2518
+
2519
+          if ($getcradmdata) {
2520
+
2521
+            if ($provider == "tnx") {
2522
+
2523
+                $getalwd = $this->connection->prepare('SELECT `user_id`, `tnx_groups_allowed`, `tnx_users_allowed` FROM `*PREFIX*sms_relent_subac`');
2524
+                $getalwdres = $getalwd->execute();
2525
+
2526
+                $upchck = 0;
2527
+                $seldataarr = [];
2528
+                $groupsPerProvider = '';
2529
+                $usersPerProvider = '';
2530
+                while ($crntrestr = $getalwdres->fetch()) {
2531
+                       if ($crntrestr['user_id'] != $userId) {
2532
+                           $seldataarr[] = ['userid' => $crntrestr['user_id'], 'groupsallowed' => $crntrestr['tnx_groups_allowed'], 'usersallowed' => $crntrestr['tnx_users_allowed']];
2533
+                       } else {
2534
+                           $upchck++;
2535
+                           $groupsPerProvider = $crntrestr['tnx_groups_allowed'];
2536
+                           $usersPerProvider = $crntrestr['tnx_users_allowed'];
2537
+                       }
2538
+                }
2539
+                $getalwdres->closeCursor();
2540
+
2541
+
2542
+            } elseif ($provider == "plv") {
2543
+
2544
+                $getalwd = $this->connection->prepare('SELECT `user_id`, `plv_groups_allowed`, `plv_users_allowed` FROM `*PREFIX*sms_relent_subac`');
2545
+                $getalwdres = $getalwd->execute();
2546
+
2547
+                $upchck = 0;
2548
+                $seldataarr = [];
2549
+                $groupsPerProvider = '';
2550
+                $usersPerProvider = '';
2551
+                while ($crntrestr = $getalwdres->fetch()) {
2552
+                       if ($crntrestr['user_id'] != $userId) {
2553
+                           $seldataarr[] = ['userid' => $crntrestr['user_id'], 'groupsallowed' => $crntrestr['plv_groups_allowed'], 'usersallowed' => $crntrestr['plv_users_allowed']];
2554
+                       } else {
2555
+                           $upchck++;
2556
+                           $groupsPerProvider = $crntrestr['plv_groups_allowed'];
2557
+                           $usersPerProvider = $crntrestr['plv_users_allowed'];
2558
+                       }
2559
+                }
2560
+                $getalwdres->closeCursor();
2561
+
2562
+            } elseif ($provider == "twl") {
2563
+
2564
+                $getalwd = $this->connection->prepare('SELECT `user_id`, `twl_groups_allowed`, `twl_users_allowed` FROM `*PREFIX*sms_relent_subac`');
2565
+                $getalwdres = $getalwd->execute();
2566
+
2567
+                $upchck = 0;
2568
+                $seldataarr = [];
2569
+                $groupsPerProvider = '';
2570
+                $usersPerProvider = '';
2571
+                while ($crntrestr = $getalwdres->fetch()) {
2572
+                       if ($crntrestr['user_id'] != $userId) {
2573
+                           $seldataarr[] = ['userid' => $crntrestr['user_id'], 'groupsallowed' => $crntrestr['twl_groups_allowed'], 'usersallowed' => $crntrestr['twl_users_allowed']];
2574
+                       } else {
2575
+                           $upchck++;
2576
+                           $groupsPerProvider = $crntrestr['twl_groups_allowed'];
2577
+                           $usersPerProvider = $crntrestr['twl_users_allowed'];
2578
+                       }
2579
+                }
2580
+                $getalwdres->closeCursor();
2581
+
2582
+            } elseif ($provider == "flr") {
2583
+
2584
+                $getalwd = $this->connection->prepare('SELECT `user_id`, `flr_groups_allowed`, `flr_users_allowed` FROM `*PREFIX*sms_relent_subac`');
2585
+                $getalwdres = $getalwd->execute();
2586
+
2587
+                $upchck = 0;
2588
+                $seldataarr = [];
2589
+                $groupsPerProvider = '';
2590
+                $usersPerProvider = '';
2591
+                while ($crntrestr = $getalwdres->fetch()) {
2592
+                       if ($crntrestr['user_id'] != $userId) {
2593
+                           $seldataarr[] = ['userid' => $crntrestr['user_id'], 'groupsallowed' => $crntrestr['flr_groups_allowed'], 'usersallowed' => $crntrestr['flr_users_allowed']];
2594
+                       } else {
2595
+                           $upchck++;
2596
+                           $groupsPerProvider = $crntrestr['flr_groups_allowed'];
2597
+                           $usersPerProvider = $crntrestr['flr_users_allowed'];
2598
+                       }
2599
+                }
2600
+                $getalwdres->closeCursor();
2601
+
2602
+            }
2603
+
2604
+
2605
+            if ($seldataarr) {
2606
+
2607
+                // Check if any of the current users are among the already saved ones (for the same provider)
2608
+                $usrchck = 0;
2609
+                $usrmsgarr = [];
2610
+                foreach ($users as $ukey => $uvalue) {
2611
+                         if ($uvalue != '') {
2612
+                             for ($j = 0; $j < count($seldataarr); $j++) {
2613
+                                  if (str_contains($seldataarr[$j]['usersallowed'], $uvalue)) {
2614
+                                      $usrchck++;
2615
+                                      $usrmsgarr[] = "The admin " . $seldataarr[$j]['userid'] . " has already allowed the user " . $uvalue . " to access his API keys for this provider.";
2616
+                                  }
2617
+                             }
2618
+                         }
2619
+                }
2620
+
2621
+                // Check if any of the current groups are among the already saved ones (for the same provider)
2622
+                $grchck = 0;
2623
+                $grmsgarr = [];
2624
+                foreach ($groups as $gkey => $gvalue) {
2625
+                         if ($gvalue != '') {
2626
+                             for ($k = 0; $k < count($seldataarr); $k++) {
2627
+                                  if (str_contains($seldataarr[$k]['groupsallowed'], $gvalue)) {
2628
+                                      $grchck++;
2629
+                                      $grmsgarr[] = "The admin " . $seldataarr[$k]['userid'] . " has already allowed the group " . $gvalue . " to access his API keys for this provider.";
2630
+                                  }
2631
+                             }
2632
+                         }
2633
+                }
2634
+
2635
+                if ($usrchck == 0 && $grchck == 0) {
2636
+
2637
+
2638
+                    // Remove the previously saved API keys for each user in the specified groups, for the current provider
2639
+                    if ($groupsPerProvider != '') {
2640
+
2641
+                        $groupsPerProvarr = explode("|", $groupsPerProvider);
2642
+                        foreach ($groupsPerProvarr as $prgrkey => $prgrvalue) {
2643
+
2644
+                                 if ($prgrvalue != "admin" && $prgrvalue != '') {
2645
+
2646
+                                     // Get all the users that belong to the group
2647
+	                             $getusringrp = $this->connection->prepare('SELECT `gid`, `uid` FROM `*PREFIX*group_user` WHERE `gid` = ?');
2648
+			             $getusringrpres = $getusringrp->execute([$prgrvalue]);
2649
+
2650
+                                     $usersingroup = [];
2651
+			             while ($getusrnm = $getusringrpres->fetch()) {
2652
+                                            if ($getusrnm['uid'] != $userId) {
2653
+
2654
+		                                // Ensure the current user is not an admin
2655
+                                                if (!in_array($getusrnm['uid'], $usersadmin)) {
2656
+                                                     $usersingroup[] = $getusrnm['uid'];
2657
+                                                }
2658
+                                            }
2659
+                                     }
2660
+			             $getusringrpres->closeCursor();
2661
+
2662
+                                     if ($usersingroup) {
2663
+                                         $msgtosend = $this->removeusercredentials($userId, $usersingroup, $provider, $telapiKey, $telpubKey, $telmsgprofid, $telsendername, $plivoapikey, 
2664
+                                                                               $plivoapisecret, $plivosendernm, $twilapikey, $twilapisecret, $twilsendernm, $flowapikey, $flowapisecret);
2665
+                                     }
2666
+                                 }
2667
+
2668
+                        }
2669
+                    }
2670
+
2671
+
2672
+                    // Remove the previously saved API keys for each user, for the current provider
2673
+                    if ($usersPerProvider != '') {
2674
+
2675
+                        $usersPerProvarr = explode("|", $usersPerProvider);
2676
+                        if ($usersPerProvarr) {
2677
+
2678
+                            $ctusernamearrpr = [];
2679
+                            foreach ($usersPerProvarr as $usrKeypr => $usrValuepr) {
2680
+
2681
+		                 // Get the username for this Display Name
2682
+		                 $getacdataunmpr = $this->connection->prepare('SELECT `uid`, `name`, `value` FROM `*PREFIX*accounts_data` WHERE `name` = ? AND `value` = ?');
2683
+		                 $getacdataunmprres = $getacdataunmpr->execute(['displayname', $usrValuepr]);
2684
+		                 $acdatausrnamepr = $getacdataunmprres->fetch();
2685
+                                 if ($acdatausrnamepr['uid'] != $userId) {
2686
+
2687
+		                     // Ensure the current user is not an admin
2688
+                                     if (!in_array($acdatausrnamepr['uid'], $usersadmin)) {
2689
+                                          $ctusernamearrpr[] = $acdatausrnamepr['uid'];
2690
+                                     }
2691
+
2692
+                                 }
2693
+		                 $getacdataunmprres->closeCursor();
2694
+                            }
2695
+
2696
+                            $msgtosend = $this->removeusercredentials($userId, $ctusernamearrpr, $provider, $telapiKey, $telpubKey, $telmsgprofid, $telsendername, $plivoapikey,
2697
+                                                                      $plivoapisecret, $plivosendernm, $twilapikey, $twilapisecret, $twilsendernm, $flowapikey, $flowapisecret);
2698
+                        }
2699
+                    }
2700
+
2701
+
2702
+                    // Insert the provider's API keys for the allowed users
2703
+                    if ($users) {
2704
+
2705
+                        $ctusernamearruid = [];
2706
+                        $ctusernamearr = [];
2707
+                        foreach ($users as $usrKey => $usrValue) {
2708
+                             if ($usrValue != '') {
2709
+		                 // Get the username for this Display Name
2710
+		                 $getacdataunm = $this->connection->prepare('SELECT `uid`, `name`, `value` FROM `*PREFIX*accounts_data` WHERE `name` = ? AND `value` = ?');
2711
+		                 $getacdataunmres = $getacdataunm->execute(['displayname', $usrValue]);
2712
+		                 $acdatausrname = $getacdataunmres->fetch();
2713
+                                 if ($acdatausrname['uid'] != $userId) {
2714
+
2715
+		                     // Ensure the current user is not an admin
2716
+                                     if (!in_array($acdatausrname['uid'], $usersadmin)) {
2717
+                                         $ctusernamearruid[] = $acdatausrname['uid'];
2718
+                                         $ctusernamearr[] = $usrValue;
2719
+                                     }
2720
+
2721
+                                 }
2722
+		                 $getacdataunmres->closeCursor();
2723
+                             }
2724
+                        }
2725
+
2726
+
2727
+                        // Insert/update the allowed users in the 'sms_relent_subac' table
2728
+                        $usersalwdrs = implode("|", $ctusernamearr);
2729
+
2730
+                        if ($upchck == 0) {
2731
+
2732
+		            if ($provider == "tnx") {
2733
+
2734
+	                        $insertalwd = $this->connection->prepare('INSERT INTO `*PREFIX*sms_relent_subac` (`user_id`, `tnx_users_allowed`) VALUES (?, ?)');
2735
+	                        if ($datalwdres = $insertalwd->execute([$userId, $usersalwdrs])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
2736
+                                $upchck++;
2737
+
2738
+		            } elseif ($provider == "plv") {
2739
+
2740
+	                        $insertalwd = $this->connection->prepare('INSERT INTO `*PREFIX*sms_relent_subac` (`user_id`, `plv_users_allowed`) VALUES (?, ?)');
2741
+	                        if ($datalwdres = $insertalwd->execute([$userId, $usersalwdrs])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; } 
2742
+                                $upchck++;
2743
+
2744
+		            } elseif ($provider == "twl") {
2745
+
2746
+	                        $insertalwd = $this->connection->prepare('INSERT INTO `*PREFIX*sms_relent_subac` (`user_id`, `twl_users_allowed`) VALUES (?, ?)');
2747
+	                        if ($datalwdres = $insertalwd->execute([$userId, $usersalwdrs])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; } 
2748
+                                $upchck++;
2749
+
2750
+		            } elseif ($provider == "flr") {
2751
+
2752
+	                        $insertalwd = $this->connection->prepare('INSERT INTO `*PREFIX*sms_relent_subac` (`user_id`, `flr_users_allowed`) VALUES (?, ?)');
2753
+	                        if ($datalwdres = $insertalwd->execute([$userId, $usersalwdrs])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
2754
+                                $upchck++;
2755
+		            }
2756
+
2757
+                        } else {
2758
+
2759
+		            if ($provider == "tnx") {
2760
+
2761
+	                        $updatealwd = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_subac` SET `tnx_users_allowed` = ? WHERE `user_id` = ?');
2762
+	                        if ($datalwdres = $updatealwd->execute([$usersalwdrs, $userId])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
2763
+
2764
+		            } elseif ($provider == "plv") {
2765
+
2766
+	                        $updatealwd = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_subac` SET `plv_users_allowed` = ? WHERE `user_id` = ?');
2767
+	                        if ($datalwdres = $updatealwd->execute([$usersalwdrs, $userId])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
2768
+
2769
+		            } elseif ($provider == "twl") {
2770
+
2771
+	                        $updatealwd = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_subac` SET `twl_users_allowed` = ? WHERE `user_id` = ?');
2772
+	                        if ($datalwdres = $updatealwd->execute([$usersalwdrs, $userId])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
2773
+
2774
+		            } elseif ($provider == "flr") {
2775
+
2776
+	                        $updatealwd = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_subac` SET `flr_users_allowed` = ? WHERE `user_id` = ?');
2777
+	                        if ($datalwdres = $updatealwd->execute([$usersalwdrs, $userId])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
2778
+		            }
2779
+                        }
2780
+
2781
+                        $datalwdres->closeCursor();
2782
+
2783
+
2784
+                        // Insert/update the credentials in the 'sms_relent_settings' table, for each allowed user
2785
+                        $msgtosend = $this->updateusercredentials($userId, $ctusernamearruid, $provider, $telapiKey, $telpubKey, $telmsgprofid, $telsendername, $plivoapikey, 
2786
+                                                                  $plivoapisecret, $plivosendernm, $twilapikey, $twilapisecret, $twilsendernm, $flowapikey, $flowapisecret);
2787
+                    }
2788
+
2789
+                    // Insert the provider's API keys for the allowed groups
2790
+                    if ($groups) {
2791
+
2792
+                        $allwdgrps = [];
2793
+                        foreach ($groups as $groupkey => $groupvalue) {
2794
+
2795
+                                 if ($groupvalue != "admin" && $groupvalue != '') {
2796
+
2797
+                                     $allwdgrps[] = $groupvalue;
2798
+
2799
+                                     // Get all the users that belong to the group
2800
+			             $getacdusr = $this->connection->prepare('SELECT `gid`, `uid` FROM `*PREFIX*group_user` WHERE `gid` = ?');
2801
+			             $getacdusrres = $getacdusr->execute([$groupvalue]);
2802
+
2803
+                                     $usersingrp = [];
2804
+			             while ($getacdusrnm = $getacdusrres->fetch()) {
2805
+                                            if ($getacdusrnm['uid'] != $userId) {
2806
+
2807
+		                                // Ensure the current user is not an admin
2808
+                                                if (!in_array($getacdusrnm['uid'], $usersadmin)) {
2809
+                                                     $usersingrp[] = $getacdusrnm['uid'];
2810
+                                                }
2811
+                                            }
2812
+                                     }
2813
+			             $getacdusrres->closeCursor();
2814
+
2815
+                                     // Insert the provider's API keys for each user of the allowed groups
2816
+                                     if ($usersingrp) {
2817
+                                         $msgtosend = $this->updateusercredentials($userId, $usersingrp, $provider, $telapiKey, $telpubKey, $telmsgprofid, $telsendername, $plivoapikey, 
2818
+                                                             $plivoapisecret, $plivosendernm, $twilapikey, $twilapisecret, $twilsendernm, $flowapikey, $flowapisecret);
2819
+                                     }
2820
+                                 }
2821
+
2822
+
2823
+		                // Insert/update the allowed groups in the 'sms_relent_subac' table
2824
+		                $groupsalwdrs = implode("|", $allwdgrps);
2825
+
2826
+		                if ($upchck == 0) {
2827
+
2828
+				    if ($provider == "tnx") {
2829
+
2830
+			                $insertalwd = $this->connection->prepare('INSERT INTO `*PREFIX*sms_relent_subac` (`user_id`, `tnx_groups_allowed`) VALUES (?, ?)');
2831
+			                if ($datalwdres = $insertalwd->execute([$userId, $groupsalwdrs])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
2832
+                                        $upchck++;
2833
+
2834
+				    } elseif ($provider == "plv") {
2835
+
2836
+			                $insertalwd = $this->connection->prepare('INSERT INTO `*PREFIX*sms_relent_subac` (`user_id`, `plv_groups_allowed`) VALUES (?, ?)');
2837
+			                if ($datalwdres = $insertalwd->execute([$userId, $groupsalwdrs])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
2838
+                                        $upchck++;
2839
+
2840
+				    } elseif ($provider == "twl") {
2841
+
2842
+			                $insertalwd = $this->connection->prepare('INSERT INTO `*PREFIX*sms_relent_subac` (`user_id`, `twl_groups_allowed`) VALUES (?, ?)');
2843
+			                if ($datalwdres = $insertalwd->execute([$userId, $groupsalwdrs])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
2844
+                                        $upchck++;
2845
+
2846
+				    } elseif ($provider == "flr") {
2847
+
2848
+			                $insertalwd = $this->connection->prepare('INSERT INTO `*PREFIX*sms_relent_subac` (`user_id`, `flr_groups_allowed`) VALUES (?, ?)');
2849
+			                if ($datalwdres = $insertalwd->execute([$userId, $groupsalwdrs])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
2850
+                                        $upchck++;
2851
+				    }
2852
+
2853
+		                } else {
2854
+
2855
+				    if ($provider == "tnx") {
2856
+
2857
+			                $updatealwd = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_subac` SET `tnx_groups_allowed` = ? WHERE `user_id` = ?');
2858
+			                if ($datalwdres = $updatealwd->execute([$groupsalwdrs, $userId])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
2859
+
2860
+				    } elseif ($provider == "plv") {
2861
+
2862
+			                $updatealwd = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_subac` SET `plv_groups_allowed` = ? WHERE `user_id` = ?');
2863
+			                if ($datalwdres = $updatealwd->execute([$groupsalwdrs, $userId])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
2864
+
2865
+				    } elseif ($provider == "twl") {
2866
+
2867
+			                $updatealwd = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_subac` SET `twl_groups_allowed` = ? WHERE `user_id` = ?');
2868
+			                if ($datalwdres = $updatealwd->execute([$groupsalwdrs, $userId])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
2869
+
2870
+				    } elseif ($provider == "flr") {
2871
+
2872
+			                $updatealwd = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_subac` SET `flr_groups_allowed` = ? WHERE `user_id` = ?');
2873
+			                if ($datalwdres = $updatealwd->execute([$groupsalwdrs, $userId])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
2874
+				    }
2875
+		                }
2876
+
2877
+		                $datalwdres->closeCursor();
2878
+                        }
2879
+
2880
+                    }
2881
+
2882
+                } else {
2883
+
2884
+                        if ($grmsgarr) {
2885
+                            $grppart = implode(" ", $grmsgarr) . " A group cannot be allowed access to 2 different sets of API keys for the same SMS provider.";
2886
+                        } else { $grppart = ''; }
2887
+
2888
+                        if ($usrmsgarr) {
2889
+                            $usrpart = implode(" ", $usrmsgarr) . " A user cannot be allowed access to 2 different sets of API keys for the same SMS provider.";
2890
+                        } else { $usrpart = ''; }
2891
+
2892
+                    $msgtosend = $grppart . $usrpart;
2893
+                }
2894
+
2895
+
2896
+            } else {
2897
+
2898
+                if ($upchck == 0) {
2899
+
2900
+                    // Insert the provider's API keys for the allowed users
2901
+                    if ($users) {
2902
+
2903
+                        $ctusernamearruid = [];
2904
+                        $ctusernamearr = [];
2905
+                        foreach ($users as $usrKey => $usrValue) {
2906
+                             if ($usrValue != '') {
2907
+		                 // Get the username for this Display Name
2908
+		                 $getacdataunm = $this->connection->prepare('SELECT `uid`, `name`, `value` FROM `*PREFIX*accounts_data` WHERE `name` = ? AND `value` = ?');
2909
+		                 $getacdataunmres = $getacdataunm->execute(['displayname', $usrValue]);
2910
+		                 $acdatausrname = $getacdataunmres->fetch();
2911
+                                 if ($acdatausrname['uid'] != $userId) {
2912
+
2913
+		                     // Ensure the current user is not an admin
2914
+                                     if (!in_array($acdatausrname['uid'], $usersadmin)) {
2915
+                                         $ctusernamearruid[] = $acdatausrname['uid'];
2916
+                                         $ctusernamearr[] = $usrValue;
2917
+                                     }
2918
+
2919
+                                 }
2920
+		                 $getacdataunmres->closeCursor();
2921
+                             }
2922
+                        }
2923
+
2924
+
2925
+                        // Insert the allowed users into the 'sms_relent_subac' table
2926
+                        $usersalwdrs = implode("|", $ctusernamearr);
2927
+
2928
+		        if ($provider == "tnx") {
2929
+
2930
+	                    $insertalwd = $this->connection->prepare('INSERT INTO `*PREFIX*sms_relent_subac` (`user_id`, `tnx_users_allowed`) VALUES (?, ?)');
2931
+	                    if ($datalwdres = $insertalwd->execute([$userId, $usersalwdrs])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; } 
2932
+                            $upchck++;
2933
+
2934
+		        } elseif ($provider == "plv") {
2935
+
2936
+	                    $insertalwd = $this->connection->prepare('INSERT INTO `*PREFIX*sms_relent_subac` (`user_id`, `plv_users_allowed`) VALUES (?, ?)');
2937
+	                    if ($datalwdres = $insertalwd->execute([$userId, $usersalwdrs])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
2938
+                            $upchck++;
2939
+
2940
+		        } elseif ($provider == "twl") {
2941
+
2942
+	                    $insertalwd = $this->connection->prepare('INSERT INTO `*PREFIX*sms_relent_subac` (`user_id`, `twl_users_allowed`) VALUES (?, ?)');
2943
+	                    if ($datalwdres = $insertalwd->execute([$userId, $usersalwdrs])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
2944
+                            $upchck++;
2945
+
2946
+		        } elseif ($provider == "flr") {
2947
+
2948
+	                    $insertalwd = $this->connection->prepare('INSERT INTO `*PREFIX*sms_relent_subac` (`user_id`, `flr_users_allowed`) VALUES (?, ?)');
2949
+	                    if ($datalwdres = $insertalwd->execute([$userId, $usersalwdrs])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
2950
+                            $upchck++;
2951
+		        }
2952
+
2953
+                        $datalwdres->closeCursor();
2954
+
2955
+
2956
+                        // Insert/update the credentials in the 'sms_relent_settings' table, for each allowed user
2957
+                        $msgtosend = $this->updateusercredentials($userId, $ctusernamearruid, $provider, $telapiKey, $telpubKey, $telmsgprofid, $telsendername, $plivoapikey, 
2958
+                                                                  $plivoapisecret, $plivosendernm, $twilapikey, $twilapisecret, $twilsendernm, $flowapikey, $flowapisecret);
2959
+                    }
2960
+
2961
+                    // Insert the provider's API keys for the allowed groups
2962
+                    if ($groups) {
2963
+
2964
+                        $allwdgrps = [];
2965
+                        foreach ($groups as $groupkey => $groupvalue) {
2966
+
2967
+                                 if ($groupvalue != "admin" && $groupvalue != '') {
2968
+
2969
+                                     $allwdgrps[] = $groupvalue;
2970
+
2971
+                                     // Get all the users that belong to the group
2972
+			             $getacdusr = $this->connection->prepare('SELECT `gid`, `uid` FROM `*PREFIX*group_user` WHERE `gid` = ?');
2973
+			             $getacdusrres = $getacdusr->execute([$groupvalue]);
2974
+
2975
+                                     $usersingrp = [];
2976
+			             while ($getacdusrnm = $getacdusrres->fetch()) {
2977
+                                            if ($getacdusrnm['uid'] != $userId) {
2978
+
2979
+		                                // Ensure the current user is not an admin
2980
+                                                if (!in_array($getacdusrnm['uid'], $usersadmin)) {
2981
+                                                     $usersingrp[] = $getacdusrnm['uid'];
2982
+                                                }
2983
+                                            }
2984
+                                     }
2985
+			             $getacdusrres->closeCursor();
2986
+
2987
+                                     // Insert the provider's API keys for each user of the allowed groups
2988
+                                     if ($usersingrp) {
2989
+                                         $msgtosend = $this->updateusercredentials($userId, $usersingrp, $provider, $telapiKey, $telpubKey, $telmsgprofid, $telsendername, $plivoapikey, 
2990
+                                                             $plivoapisecret, $plivosendernm, $twilapikey, $twilapisecret, $twilsendernm, $flowapikey, $flowapisecret);
2991
+                                     }
2992
+                                 }
2993
+
2994
+
2995
+		                // Insert the allowed groups into the 'sms_relent_subac' table
2996
+		                $groupsalwdrs = implode("|", $allwdgrps);
2997
+
2998
+                                if ($upchck == 0) {
2999
+
3000
+				    if ($provider == "tnx") {
3001
+
3002
+			                $insertalwd = $this->connection->prepare('INSERT INTO `*PREFIX*sms_relent_subac` (`user_id`, `tnx_groups_allowed`) VALUES (?, ?)');
3003
+			                if ($datalwdres = $insertalwd->execute([$userId, $groupsalwdrs])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; } 
3004
+
3005
+				    } elseif ($provider == "plv") {
3006
+
3007
+			                $insertalwd = $this->connection->prepare('INSERT INTO `*PREFIX*sms_relent_subac` (`user_id`, `plv_groups_allowed`) VALUES (?, ?)');
3008
+			                if ($datalwdres = $insertalwd->execute([$userId, $groupsalwdrs])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; } 
3009
+
3010
+				    } elseif ($provider == "twl") {
3011
+
3012
+			                $insertalwd = $this->connection->prepare('INSERT INTO `*PREFIX*sms_relent_subac` (`user_id`, `twl_groups_allowed`) VALUES (?, ?)');
3013
+			                if ($datalwdres = $insertalwd->execute([$userId, $groupsalwdrs])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; } 
3014
+
3015
+				    } elseif ($provider == "flr") {
3016
+
3017
+			                $insertalwd = $this->connection->prepare('INSERT INTO `*PREFIX*sms_relent_subac` (`user_id`, `flr_groups_allowed`) VALUES (?, ?)');
3018
+			                if ($datalwdres = $insertalwd->execute([$userId, $groupsalwdrs])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; } 
3019
+				    }
3020
+
3021
+                                } else {
3022
+
3023
+				    if ($provider == "tnx") {
3024
+
3025
+			                $updatealwd = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_subac` SET `tnx_groups_allowed` = ? WHERE `user_id` = ?');
3026
+			                if ($datalwdres = $updatealwd->execute([$groupsalwdrs, $userId])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
3027
+
3028
+				    } elseif ($provider == "plv") {
3029
+
3030
+			                $updatealwd = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_subac` SET `plv_groups_allowed` = ? WHERE `user_id` = ?');
3031
+			                if ($datalwdres = $updatealwd->execute([$groupsalwdrs, $userId])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
3032
+
3033
+				    } elseif ($provider == "twl") {
3034
+
3035
+			                $updatealwd = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_subac` SET `twl_groups_allowed` = ? WHERE `user_id` = ?');
3036
+			                if ($datalwdres = $updatealwd->execute([$groupsalwdrs, $userId])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
3037
+
3038
+				    } elseif ($provider == "flr") {
3039
+
3040
+			                $updatealwd = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_subac` SET `flr_groups_allowed` = ? WHERE `user_id` = ?');
3041
+			                if ($datalwdres = $updatealwd->execute([$groupsalwdrs, $userId])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
3042
+				    }
3043
+
3044
+                                }
3045
+
3046
+		                $datalwdres->closeCursor();
3047
+                        }
3048
+
3049
+                    }
3050
+
3051
+                } else {
3052
+
3053
+                    // Remove the previously saved API keys for each user in the specified groups, for the current provider
3054
+                    if ($groupsPerProvider != '') {
3055
+
3056
+                        $groupsPerProvarr = explode("|", $groupsPerProvider);
3057
+                        foreach ($groupsPerProvarr as $prgrkey => $prgrvalue) {
3058
+
3059
+                                 if ($prgrvalue != "admin" && $prgrvalue != '') {
3060
+
3061
+                                     // Get all the users that belong to the group
3062
+	                             $getusringrp = $this->connection->prepare('SELECT `gid`, `uid` FROM `*PREFIX*group_user` WHERE `gid` = ?');
3063
+			             $getusringrpres = $getusringrp->execute([$prgrvalue]);
3064
+
3065
+                                     $usersingroup = [];
3066
+			             while ($getusrnm = $getusringrpres->fetch()) {
3067
+                                            if ($getusrnm['uid'] != $userId) {
3068
+
3069
+		                                // Ensure the current user is not an admin
3070
+                                                if (!in_array($getusrnm['uid'], $usersadmin)) {
3071
+                                                     $usersingroup[] = $getusrnm['uid'];
3072
+                                                }
3073
+                                            }
3074
+                                     }
3075
+			             $getusringrpres->closeCursor();
3076
+
3077
+                                     if ($usersingroup) {
3078
+                                         $msgtosend = $this->removeusercredentials($userId, $usersingroup, $provider, $telapiKey, $telpubKey, $telmsgprofid, $telsendername, $plivoapikey, 
3079
+                                                             $plivoapisecret, $plivosendernm, $twilapikey, $twilapisecret, $twilsendernm, $flowapikey, $flowapisecret);
3080
+                                     }
3081
+                                 }
3082
+
3083
+                        }
3084
+                    }
3085
+
3086
+
3087
+                    // Remove the previously saved API keys for each user, for the current provider
3088
+                    if ($usersPerProvider != '') {
3089
+
3090
+                        $usersPerProvarr = explode("|", $usersPerProvider);
3091
+                        if ($usersPerProvarr) {
3092
+
3093
+                            $ctusernamearrpr = [];
3094
+                            foreach ($usersPerProvarr as $usrKeypr => $usrValuepr) {
3095
+
3096
+		                 // Get the username for this Display Name
3097
+		                 $getacdataunmpr = $this->connection->prepare('SELECT `uid`, `name`, `value` FROM `*PREFIX*accounts_data` WHERE `name` = ? AND `value` = ?');
3098
+		                 $getacdataunmprres = $getacdataunmpr->execute(['displayname', $usrValuepr]);
3099
+		                 $acdatausrnamepr = $getacdataunmprres->fetch();
3100
+                                 if ($acdatausrnamepr['uid'] != $userId) {
3101
+
3102
+		                     // Ensure the current user is not an admin
3103
+                                     if (!in_array($acdatausrnamepr['uid'], $usersadmin)) {
3104
+                                          $ctusernamearrpr[] = $acdatausrnamepr['uid'];
3105
+                                     }
3106
+
3107
+                                 }
3108
+		                 $getacdataunmprres->closeCursor();
3109
+                            }
3110
+
3111
+                            $msgtosend = $this->removeusercredentials($userId, $ctusernamearrpr, $provider, $telapiKey, $telpubKey, $telmsgprofid, $telsendername, $plivoapikey,
3112
+                                                                      $plivoapisecret, $plivosendernm, $twilapikey, $twilapisecret, $twilsendernm, $flowapikey, $flowapisecret);
3113
+                        }
3114
+                    }
3115
+
3116
+
3117
+
3118
+                    // Insert the provider's API keys for the allowed users
3119
+                    if ($users) {
3120
+
3121
+                        $ctusernamearruid = [];
3122
+                        $ctusernamearr = [];
3123
+                        foreach ($users as $usrKey => $usrValue) {
3124
+                             if ($usrValue != '') {
3125
+		                 // Get the username for this Display Name
3126
+		                 $getacdataunm = $this->connection->prepare('SELECT `uid`, `name`, `value` FROM `*PREFIX*accounts_data` WHERE `name` = ? AND `value` = ?');
3127
+		                 $getacdataunmres = $getacdataunm->execute(['displayname', $usrValue]);
3128
+		                 $acdatausrname = $getacdataunmres->fetch();
3129
+                                 if ($acdatausrname['uid'] != $userId) {
3130
+
3131
+		                     // Ensure the current user is not an admin
3132
+                                     if (!in_array($acdatausrname['uid'], $usersadmin)) {
3133
+                                         $ctusernamearruid[] = $acdatausrname['uid'];
3134
+                                         $ctusernamearr[] = $usrValue;
3135
+
3136
+                                     }
3137
+
3138
+                                 }
3139
+		                 $getacdataunmres->closeCursor();
3140
+                             }
3141
+                        }
3142
+
3143
+
3144
+                        // Update the allowed users in the 'sms_relent_subac' table
3145
+                        $usersalwdrs = implode("|", $ctusernamearr);
3146
+
3147
+		        if ($provider == "tnx") {
3148
+
3149
+	                    $updatealwd = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_subac` SET `tnx_users_allowed` = ? WHERE `user_id` = ?');
3150
+	                    if ($datalwdres = $updatealwd->execute([$usersalwdrs, $userId])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
3151
+
3152
+		        } elseif ($provider == "plv") {
3153
+
3154
+	                    $updatealwd = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_subac` SET `plv_users_allowed` = ? WHERE `user_id` = ?');
3155
+	                    if ($datalwdres = $updatealwd->execute([$usersalwdrs, $userId])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
3156
+
3157
+		        } elseif ($provider == "twl") {
3158
+
3159
+	                    $updatealwd = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_subac` SET `twl_users_allowed` = ? WHERE `user_id` = ?');
3160
+	                    if ($datalwdres = $updatealwd->execute([$usersalwdrs, $userId])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
3161
+
3162
+		        } elseif ($provider == "flr") {
3163
+
3164
+	                    $updatealwd = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_subac` SET `flr_users_allowed` = ? WHERE `user_id` = ?');
3165
+	                    if ($datalwdres = $updatealwd->execute([$usersalwdrs, $userId])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
3166
+		        }
3167
+
3168
+                        $datalwdres->closeCursor();
3169
+
3170
+
3171
+                        // Insert/update the credentials in the 'sms_relent_settings' table, for each allowed user
3172
+                        $msgtosend = $this->updateusercredentials($userId, $ctusernamearruid, $provider, $telapiKey, $telpubKey, $telmsgprofid, $telsendername, $plivoapikey, 
3173
+                                                                  $plivoapisecret, $plivosendernm, $twilapikey, $twilapisecret, $twilsendernm, $flowapikey, $flowapisecret);
3174
+                    }
3175
+
3176
+                    // Insert the provider's API keys for the allowed groups
3177
+                    if ($groups) {
3178
+
3179
+                        $allwdgrps = [];
3180
+                        foreach ($groups as $groupkey => $groupvalue) {
3181
+
3182
+                                 if ($groupvalue != "admin" && $groupvalue != '') {
3183
+
3184
+                                     $allwdgrps[] = $groupvalue;
3185
+
3186
+                                     // Get all the users that belong to the group
3187
+			             $getacdusr = $this->connection->prepare('SELECT `gid`, `uid` FROM `*PREFIX*group_user` WHERE `gid` = ?');
3188
+			             $getacdusrres = $getacdusr->execute([$groupvalue]);
3189
+
3190
+                                     $usersingrp = [];
3191
+			             while ($getacdusrnm = $getacdusrres->fetch()) {
3192
+                                            if ($getacdusrnm['uid'] != $userId) {
3193
+
3194
+		                                // Ensure the current user is not an admin
3195
+                                                if (!in_array($getacdusrnm['uid'], $usersadmin)) {
3196
+                                                     $usersingrp[] = $getacdusrnm['uid'];
3197
+                                                }
3198
+                                            }
3199
+                                     }
3200
+			             $getacdusrres->closeCursor();
3201
+
3202
+                                     // Insert the provider's API keys for each user of the allowed groups
3203
+                                     if ($usersingrp) {
3204
+                                         $msgtosend = $this->updateusercredentials($userId, $usersingrp, $provider, $telapiKey, $telpubKey, $telmsgprofid, $telsendername, $plivoapikey, 
3205
+                                                             $plivoapisecret, $plivosendernm, $twilapikey, $twilapisecret, $twilsendernm, $flowapikey, $flowapisecret);
3206
+                                     }
3207
+                                 }
3208
+
3209
+
3210
+		                 // Update the allowed groups in the 'sms_relent_subac' table
3211
+		                 $groupsalwdrs = implode("|", $allwdgrps);
3212
+
3213
+				 if ($provider == "tnx") {
3214
+
3215
+			             $updatealwd = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_subac` SET `tnx_groups_allowed` = ? WHERE `user_id` = ?');
3216
+			             if ($datalwdres = $updatealwd->execute([$groupsalwdrs, $userId])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
3217
+
3218
+				 } elseif ($provider == "plv") {
3219
+
3220
+			             $updatealwd = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_subac` SET `plv_groups_allowed` = ? WHERE `user_id` = ?');
3221
+			             if ($datalwdres = $updatealwd->execute([$groupsalwdrs, $userId])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
3222
+
3223
+				 } elseif ($provider == "twl") {
3224
+
3225
+			             $updatealwd = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_subac` SET `twl_groups_allowed` = ? WHERE `user_id` = ?');
3226
+			             if ($datalwdres = $updatealwd->execute([$groupsalwdrs, $userId])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
3227
+
3228
+				 } elseif ($provider == "flr") {
3229
+
3230
+			             $updatealwd = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_subac` SET `flr_groups_allowed` = ? WHERE `user_id` = ?');
3231
+			             if ($datalwdres = $updatealwd->execute([$groupsalwdrs, $userId])) { $msgtosend = 'success'; } else { $msgtosend = 'failure'; }
3232
+				 }
3233
+
3234
+		                 $datalwdres->closeCursor();
3235
+                        }
3236
+
3237
+                    }
3238
+
3239
+                }
3240
+
3241
+            }
3242
+
3243
+          } else { $msgtosend = "You have to save your credentials first, by clicking the 'Save' button at the bottom of this page, and then share your API keys with other users."; }
3244
+
3245
+          return $msgtosend;
3246
+       }
3247
+     }
3248
+
3249
+
3250
+     public function removenumberrestrictions($userId, $phoneNumber) {
3251
+
3252
+        if ($this->groupManager->isAdmin($userId)) {
3253
+
3254
+                // Remove the restrictions for the given phone number
3255
+		$delrstr = $this->connection->prepare('
3256
+		       DELETE FROM `*PREFIX*sms_relent_restrict`
3257
+		       WHERE `phone_number` = ?');
3258
+                if ($delrstrres = $delrstr->execute([$phoneNumber])) { $delresult = "success"; } else { $delresult = "failure"; }
3259
+		$delrstrres->closeCursor();
3260
+
3261
+	        $updateind = $this->connection->prepare('
3262
+                       SET @resetrec = 0;
3263
+		       UPDATE `*PREFIX*sms_relent_restrict`
3264
+		       SET `id` = @resetrec := @resetrec + 1;
3265
+                       ALTER TABLE `*PREFIX*sms_relent_restrict` auto_increment=1;');
3266
+	        $updateindres = $updateind->execute();
3267
+	        $updateindres->closeCursor();
3268
+
3269
+                return $delresult;
3270
+        }
3271
+     }
3272
+
3273
+
3274
+    /**
3275
+     * @NoAdminRequired
3276
+     */
3277
+    public function updateautoreplies($userId, $savedByDsplname, $phoneNumber, $daysOfWeek, $dailyStart, $dailyEnd, $vacationStart, $vacationEnd, $messageText) {
3278
+
3279
+        // Get the auto-reply for the current number from the 'sms_relent_autorply' table
3280
+        $getarpl = $this->connection->prepare('SELECT `user_id`, `saved_by_dsplname`, `phone_number`, `days_of_week`, `daily_start`, `daily_end`, `vacation_start`,
3281
+                                              `vacation_end`, `message_text` FROM `*PREFIX*sms_relent_autorply` WHERE `phone_number` = ?');
3282
+        $getarplresult = $getarpl->execute([$phoneNumber]);
3283
+        $crntarpl = $getarplresult->fetch();
3284
+        $getarplresult->closeCursor();
3285
+
3286
+        if ($getarplresult && !$crntarpl) {
3287
+
3288
+	    $insertpharpl = $this->connection->prepare('INSERT INTO `*PREFIX*sms_relent_autorply` (`user_id`, `saved_by_dsplname`, `phone_number`, `days_of_week`, 
3289
+                                                       `daily_start`, `daily_end`, `vacation_start`, `vacation_end`, `message_text`) VALUES
3290
+                                                        (?, ?, ?, ?, ?, ?, ?, ?, ?)');
3291
+	    if ($insertpharpl->execute([$userId, $savedByDsplname, $phoneNumber, $daysOfWeek, $dailyStart, $dailyEnd, $vacationStart, $vacationEnd, $messageText])) { 
3292
+                $messagetosend = 'success'; 
3293
+            } else { 
3294
+                $messagetosend = 'failure'; 
3295
+            }
3296
+         
3297
+        } elseif ($getarplresult && $crntarpl) {
3298
+
3299
+            if ($this->groupManager->isAdmin($userId)) {
3300
+
3301
+                $updatepharpl = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_autorply` SET `user_id` = ?, `saved_by_dsplname` = ?, `days_of_week` = ?, `daily_start` = ?,
3302
+                                                           `daily_end` = ?, `vacation_start` = ?, `vacation_end` = ?, `message_text` = ?  WHERE `phone_number` = ?');
3303
+	        if ($updatephnmbrarpl = $updatepharpl->execute([$userId, $savedByDsplname, $daysOfWeek, $dailyStart, $dailyEnd, $vacationStart, $vacationEnd, $messageText,
3304
+                                                                $phoneNumber])) { 
3305
+                    $messagetosend = 'success';
3306
+                } else { 
3307
+                    $messagetosend = 'failure'; 
3308
+                }
3309
+	        $updatephnmbrarpl->closeCursor();
3310
+
3311
+            } else {
3312
+
3313
+                // Check if the current user is the author of the existing version of the auto-reply
3314
+                if ($userId == $crntarpl['user_id']) {
3315
+
3316
+                    $updatepharpl = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_autorply` SET `user_id` = ?, `saved_by_dsplname` = ?, `days_of_week` = ?, `daily_start` = ?,
3317
+                                                               `daily_end` = ?, `vacation_start` = ?, `vacation_end` = ?, `message_text` = ?  WHERE `phone_number` = ?');
3318
+	            if ($updatephnmbrarpl = $updatepharpl->execute([$userId, $savedByDsplname, $daysOfWeek, $dailyStart, $dailyEnd, $vacationStart, $vacationEnd, $messageText,
3319
+                                                                    $phoneNumber])) { 
3320
+                        $messagetosend = 'success';
3321
+                    } else { 
3322
+                        $messagetosend = 'failure'; 
3323
+                    }
3324
+	            $updatephnmbrarpl->closeCursor();
3325
+
3326
+                } else { $messagetosend = 'not allowed'; }
3327
+            }
3328
+        }
3329
+
3330
+        return $messagetosend;
3331
+    }
3332
+
3333
+
3334
+    /**
3335
+     * @NoAdminRequired
3336
+     */
3337
+    public function removeautoreplies($userId, $phoneNumber) {
3338
+
3339
+        if ($this->groupManager->isAdmin($userId)) {
3340
+
3341
+                // Remove the auto-reply for the given phone number
3342
+		$delarpl = $this->connection->prepare('
3343
+		       DELETE FROM `*PREFIX*sms_relent_autorply`
3344
+		       WHERE `phone_number` = ?');
3345
+                if ($delarplres = $delarpl->execute([$phoneNumber])) { $delarplresult = "success"; } else { $delarplresult = "failure"; }
3346
+		$delarplres->closeCursor();
3347
+
3348
+	        $updateindarpl = $this->connection->prepare('
3349
+                       SET @resetarpl = 0;
3350
+		       UPDATE `*PREFIX*sms_relent_autorply`
3351
+		       SET `id` = @resetarpl := @resetarpl + 1;
3352
+                       ALTER TABLE `*PREFIX*sms_relent_autorply` auto_increment=1;');
3353
+	        $updateindarplres = $updateindarpl->execute();
3354
+	        $updateindarplres->closeCursor();
3355
+
3356
+                return $delarplresult;
3357
+
3358
+        } else {
3359
+                // Get the author of the auto-reply for the given phone number
3360
+		$getarplusr = $this->connection->prepare('SELECT `user_id`, `phone_number` FROM `*PREFIX*sms_relent_autorply` WHERE `phone_number` = ?');
3361
+		$getarplusrres = $getarplusr->execute([$phoneNumber]);
3362
+		$crntarpldata = $getarplusrres->fetch();
3363
+                $crntarpluser = $crntarpldata['user_id'];
3364
+		$getarplusrres->closeCursor();
3365
+
3366
+                // If the author of the auto-reply is the current user, allow the removal
3367
+                if ($crntarpluser == $userId) {
3368
+
3369
+                    // Remove the auto-reply for the given phone number
3370
+		    $delarpl = $this->connection->prepare('
3371
+		           DELETE FROM `*PREFIX*sms_relent_autorply`
3372
+		           WHERE `phone_number` = ?');
3373
+                    if ($delarplres = $delarpl->execute([$phoneNumber])) { $delarplresult = "success"; } else { $delarplresult = "failure"; }
3374
+		    $delarplres->closeCursor();
3375
+
3376
+	            $updateindarpl = $this->connection->prepare('
3377
+                           SET @resetarpl = 0;
3378
+		           UPDATE `*PREFIX*sms_relent_autorply`
3379
+		           SET `id` = @resetarpl := @resetarpl + 1;
3380
+                           ALTER TABLE `*PREFIX*sms_relent_autorply` auto_increment=1;');
3381
+	            $updateindarplres = $updateindarpl->execute();
3382
+	            $updateindarplres->closeCursor();
3383
+
3384
+                    return $delarplresult;
3385
+
3386
+                } else { 
3387
+                    return $delarplresult = 'not allowed';
3388
+                }
3389
+        }
3390
+    }
3391
+
3392
+
3393
+    public function getadminsettings($userId) {
3394
+
3395
+        if ($this->groupManager->isAdmin($userId)) {
3396
+
3397
+
3398
+	    $getsettings = $this->connection->prepare('
3399
+                            SELECT `id`, `user_id`, `telapi_key`, `tel_pub_key`, `telapi_url_rec`, `telapi_url`, `messaging_profile_id`, `nexapi_key`, `nexapi_secret`, `nexapi_url_rec`,
3400
+                                   `nexapi_url`, `twilapi_key`, `twilapi_secret`, `twilapi_url_rec`, `twilapi_url`, `flowapi_key`, `flowapi_secret`, `flowapi_url_rec`, `flowapi_url`, 
3401
+                                   `tel_sender_name`, `nex_sender_name`, `twil_sender_name`, `flow_sender_name`, `messagesperpage`, `get_notify`, `notification_email`, `getsmsinemail`, 
3402
+                                   `show_all_messages`
3403
+			    FROM  `*PREFIX*sms_relent_settings`
3404
+			    WHERE `user_id` = ?');
3405
+
3406
+	    $resultsettings = $getsettings->execute([$userId]);
3407
+
3408
+            $settingsadm = $resultsettings->fetch();
3409
+
3410
+	    $resultsettings->closeCursor();
3411
+
3412
+	    if ($settingsadm) {
3413
+
3414
+		    if ($settingsadm['telapi_key'] != '') {
3415
+
3416
+		        // Send a placeholder to the browser, instead of the real API key
3417
+		        $settingsadm['telapi_key'] = "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20";
3418
+		    }
3419
+		    if ($settingsadm['tel_pub_key'] != '') {
3420
+		        $settingsadm['tel_pub_key'] = "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20";
3421
+		    }
3422
+		    if ($settingsadm['messaging_profile_id'] != '') {
3423
+		        $settingsadm['messaging_profile_id'] = "%20%20%20%20%20%20%20%20%20%20%20%20";
3424
+		    }
3425
+		    if ($settingsadm['nexapi_key'] != '') {
3426
+		        $settingsadm['nexapi_key'] = "%20%20%20%20%20%20%20%20%20";
3427
+		    }
3428
+		    if ($settingsadm['nexapi_secret'] != '') {
3429
+		        $settingsadm['nexapi_secret'] = "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20";
3430
+		    }
3431
+		    if ($settingsadm['twilapi_key'] != '') {
3432
+		        $settingsadm['twilapi_key'] = "%20%20%20%20%20%20%20%20%20";
3433
+		    }
3434
+		    if ($settingsadm['twilapi_secret'] != '') {
3435
+		        $settingsadm['twilapi_secret'] = "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20";
3436
+		    }
3437
+		    if ($settingsadm['flowapi_key'] != '') {
3438
+		        $settingsadm['flowapi_key'] = "%20%20%20%20%20%20%20%20%20";
3439
+		    }
3440
+		    if ($settingsadm['flowapi_secret'] != '') {
3441
+		        $settingsadm['flowapi_secret'] = "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20";
3442
+		    }
3443
+
3444
+
3445
+		    // Get the Display Name of the current admin
3446
+		    $getacdatadn = $this->connection->prepare('SELECT `uid`, `name`, `value` FROM `*PREFIX*accounts_data` WHERE `uid` = ? AND `name` = ?');
3447
+		    $getacdatadnres = $getacdatadn->execute([$userId, 'displayname']);
3448
+		    $acdatausrdnadm = $getacdatadnres->fetch();
3449
+		    $cruserdname = $acdatausrdnadm['value'];
3450
+		    $getacdatadnres->closeCursor();
3451
+
3452
+		    // Get all the restrictions on phone numbers
3453
+		    $getrestr = $this->connection->prepare('SELECT `saved_by_dsplname`, `phone_number`, `groups`, `users` FROM `*PREFIX*sms_relent_restrict`');
3454
+		    $getrestres = $getrestr->execute();
3455
+
3456
+		    $restrictedArr = [];
3457
+		    while ($restrfetched = $getrestres->fetch()) {
3458
+		           $restrictedArr[] = $restrfetched;
3459
+		    }
3460
+		    $getrestres->closeCursor();
3461
+
3462
+		    if ($restrictedArr) { $restrictedUsers = $restrictedArr; } else { $restrictedUsers = ''; }
3463
+
3464
+
3465
+		    // Get the name of all the groups
3466
+		    $getgroups = $this->connection->prepare('SELECT `gid`, `displayname` FROM `*PREFIX*groups`');
3467
+		    $getgroupsres = $getgroups->execute();
3468
+
3469
+		    $groupsArr = [];
3470
+                    $allgroupswadmarr = [];
3471
+		    while ($groupsfetched = $getgroupsres->fetch()) {
3472
+
3473
+		           $groupsArr[] = $groupsfetched['gid'];
3474
+                           if ($groupsfetched['gid'] != 'admin') { $allgroupswadmarr[] = $groupsfetched['gid']; }
3475
+		    }
3476
+		    $getgroupsres->closeCursor();
3477
+
3478
+		    if ($groupsArr) { $allgroups = $groupsArr; } else { $allgroups = ''; }
3479
+                    if ($allgroupswadmarr) { $allgroupswadm = $allgroupswadmarr; } else { $allgroupswadm = ''; }
3480
+
3481
+		    // Get the users that belong to the 'admin' group
3482
+		    $getadmnsc = $this->connection->prepare('SELECT `gid`, `uid` FROM `*PREFIX*group_user` WHERE `gid` = ?');
3483
+		    $getadmnscres = $getadmnsc->execute(['admin']);
3484
+
3485
+		    $usersadminsc = [];
3486
+		    while ($getadmnusrsc = $getadmnscres->fetch()) {
3487
+		           $usersadminsc[] = $getadmnusrsc['uid'];
3488
+		    }
3489
+		    $getadmnscres->closeCursor();
3490
+
3491
+
3492
+		    // Get the display name of all the users
3493
+		    $getusers = $this->connection->prepare('SELECT `uid`, `name`, `value` FROM `*PREFIX*accounts_data` WHERE `name` = ?');
3494
+		    $getusersres = $getusers->execute(['displayname']);
3495
+
3496
+		    $usersArr = [];
3497
+                    $alluserswadmarr = [];
3498
+		    while ($usersfetched = $getusersres->fetch()) {
3499
+
3500
+		           $usersArr[] = $usersfetched['value'];
3501
+                           if (!in_array($usersfetched['uid'], $usersadminsc)) { $alluserswadmarr[] = $usersfetched['value']; }
3502
+		    }
3503
+		    $getusersres->closeCursor();
3504
+
3505
+		    if ($usersArr) { $allusers = $usersArr; } else { $allusers = ''; }
3506
+                    if ($alluserswadmarr) { $alluserswadm = $alluserswadmarr; } else { $alluserswadm = ''; }
3507
+
3508
+                    // Get the groups and users that are allowed to use the API Keys, for each provider
3509
+                    $getalwdall = $this->connection->prepare('SELECT `user_id`, `tnx_groups_allowed`, `tnx_users_allowed`, `plv_groups_allowed`, `plv_users_allowed`,
3510
+                                                             `twl_groups_allowed`, `twl_users_allowed`, `flr_groups_allowed`, `flr_users_allowed` FROM `*PREFIX*sms_relent_subac`
3511
+                                                              WHERE `user_id` = ?');
3512
+                    $getalwdallres = $getalwdall->execute([$userId]);
3513
+                    $crtdtrow = $getalwdallres->fetch();
3514
+                    if ($crtdtrow) {
3515
+                        $allowedgrps = ['tnx_groups_allowed' => $crtdtrow['tnx_groups_allowed'], 'tnx_users_allowed' => $crtdtrow['tnx_users_allowed'], 
3516
+                                        'plv_groups_allowed' => $crtdtrow['plv_groups_allowed'], 'plv_users_allowed' => $crtdtrow['plv_users_allowed'],
3517
+                                        'twl_groups_allowed' => $crtdtrow['twl_groups_allowed'], 'twl_users_allowed' => $crtdtrow['twl_users_allowed'],
3518
+                                        'flr_groups_allowed' => $crtdtrow['flr_groups_allowed'], 'flr_users_allowed' => $crtdtrow['flr_users_allowed']];
3519
+                        $getalwdallres->closeCursor();
3520
+                    } else { $allowedgrps = []; }
3521
+
3522
+
3523
+                    $settingsadm['admdisplayname'] = $cruserdname;
3524
+                    $settingsadm['restrictions'] = $restrictedUsers;
3525
+                    $settingsadm['allgroups'] = $allgroups;
3526
+                    $settingsadm['allusers'] = $allusers;
3527
+                    $settingsadm['allgroupswadm'] = $allgroupswadm;
3528
+                    $settingsadm['alluserswadm'] = $alluserswadm;  
3529
+                    $settingsadm['allowedkeysuse'] = $allowedgrps;
3530
+
3531
+		    return $settingsadm;
3532
+	    }
3533
+        }
3534
+     }
3535
+
3536
+
3537
+     /**
3538
+      * @NoAdminRequired
3539
+      *
3540
+      */
3541
+     public function updatesettings($userId, $telapiUrlRec, $telapiUrl, $nexapiUrlRec, $nexapiUrl, $twilapiUrlRec, $twilapiUrl, $flowapiUrlRec, $flowapiUrl, $messagesperpage, 
3542
+                                    $getNotify, $notificationEmail, $getsmsinemail, $showDisplayNames, $addDisplayNames, $msgCheckInterval) {
3543
+        $upsettings = $this->connection->prepare('
3544
+                        SELECT `id`, `user_id`, `telapi_key`, `tel_pub_key`, `telapi_url_rec`, `telapi_url`, `messaging_profile_id`, `nexapi_key`, `nexapi_secret`, `nexapi_url_rec`,
3545
+                           `nexapi_url`, `twilapi_key`, `twilapi_secret`, `twilapi_url_rec`, `twilapi_url`, `flowapi_key`, `flowapi_secret`, `flowapi_url_rec`, `flowapi_url`, 
3546
+                           `tel_sender_name`, `nex_sender_name`, `twil_sender_name`, `flow_sender_name`, `messagesperpage`, `get_notify`, `notification_email`, `getsmsinemail`, 
3547
+                           `show_all_messages`, `show_display_names`, `add_display_names`, `available_numbers`, `msg_check_interval`, `new_message_rcd`
3548
+		        FROM  `*PREFIX*sms_relent_settings`
3549
+		        WHERE `user_id` = ?');
3550
+
3551
+        $resultstng = $upsettings->execute([$userId]);
3552
+
3553
+        $rowup = $resultstng->fetch();
3554
+
3555
+        $resultstng->closeCursor();
3556
+
3557
+        if ($resultstng && !$rowup) {
3558
+
3559
+	    $sql = $this->connection->prepare('
3560
+				INSERT INTO `*PREFIX*sms_relent_settings`
3561
+					(`user_id`, `telapi_url_rec`, `telapi_url`, `nexapi_url_rec`, `nexapi_url`, `twilapi_url_rec`, `twilapi_url`, `flowapi_url_rec`, `flowapi_url`, 
3562
+                                         `messagesperpage`, `get_notify`, `notification_email`, `getsmsinemail`, `show_display_names`, `add_display_names`, `msg_check_interval`)
3563
+				VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
3564
+			');
3565
+	    $sql->execute([$userId, $telapiUrlRec, $telapiUrl, $nexapiUrlRec, $nexapiUrl, $twilapiUrlRec, $twilapiUrl, $flowapiUrlRec, $flowapiUrl, $messagesperpage, $getNotify, 
3566
+                           $notificationEmail, $getsmsinemail, $showDisplayNames, $addDisplayNames, $msgCheckInterval]);
3567
+
3568
+        } elseif ($resultstng && $rowup) {
3569
+
3570
+	    $sqlupdatedb = $this->connection->prepare('
3571
+			UPDATE `*PREFIX*sms_relent_settings`
3572
+			SET `telapi_url_rec` = ?, `telapi_url` = ?, `nexapi_url_rec` = ?, `nexapi_url` = ?, `twilapi_url_rec` = ?, `twilapi_url` = ?, `flowapi_url_rec` = ?, 
3573
+                            `flowapi_url` = ?, `messagesperpage` = ?, `get_notify` = ?, `notification_email` = ?, `getsmsinemail` = ?, `show_display_names` = ?, `add_display_names` = ?,
3574
+                            `msg_check_interval` = ?
3575
+	                WHERE `user_id` = ?');
3576
+	    $updateRes = $sqlupdatedb->execute([$telapiUrlRec, $telapiUrl, $nexapiUrlRec, $nexapiUrl, $twilapiUrlRec, $twilapiUrl, $flowapiUrlRec, $flowapiUrl, $messagesperpage, 
3577
+                                                $getNotify, $notificationEmail, $getsmsinemail, $showDisplayNames, $addDisplayNames, $msgCheckInterval, $userId]);
3578
+	    $updateRes->closeCursor();
3579
+
3580
+	}
3581
+     }
3582
+
3583
+
3584
+     public function updateadminsettings($userId, $telapiKey, $telPubKey, $telapiUrlRec, $telapiUrl, $messagingProfileId, $nexapiKey, $nexapiSecret, $nexapiUrlRec, $nexapiUrl,
3585
+                                         $telSenderName, $nexSenderName, $twilapiKey, $twilapiSecret, $twilapiUrlRec, $twilapiUrl, $twilSenderName, $flowapiKey, $flowapiSecret, 
3586
+                                         $flowapiUrlRec, $flowapiUrl, $showAllMessages) {
3587
+
3588
+        if ($this->groupManager->isAdmin($userId)) {
3589
+
3590
+            $upsettings = $this->connection->prepare('
3591
+                        SELECT `id`, `user_id`, `telapi_key`, `tel_pub_key`, `telapi_url_rec`, `telapi_url`, `messaging_profile_id`, `nexapi_key`, `nexapi_secret`, `nexapi_url_rec`,
3592
+                           `nexapi_url`, `twilapi_key`, `twilapi_secret`, `twilapi_url_rec`, `twilapi_url`, `flowapi_key`, `flowapi_secret`, `flowapi_url_rec`, `flowapi_url`, 
3593
+                           `tel_sender_name`, `nex_sender_name`, `twil_sender_name`, `flow_sender_name`, `messagesperpage`, `get_notify`, `notification_email`, `getsmsinemail`, 
3594
+                           `show_all_messages`, `show_display_names`, `add_display_names`
3595
+		        FROM  `*PREFIX*sms_relent_settings`
3596
+		        WHERE `user_id` = ?');
3597
+
3598
+            $resultstng = $upsettings->execute([$userId]);
3599
+
3600
+            $rowup = $resultstng->fetch();
3601
+
3602
+            $resultstng->closeCursor();
3603
+
3604
+            if ($resultstng && !$rowup) {
3605
+
3606
+	        if ($telapiKey != '') {
3607
+	            $telapikeystrenc = $this->crypto->encrypt($telapiKey);             
3608
+	        } else { $telapikeystrenc = ''; }
3609
+
3610
+	        if ($telPubKey != '') {
3611
+	            $telpubkeystrenc =  $this->crypto->encrypt($telPubKey);             
3612
+	        } else { $telpubkeystrenc = ''; }
3613
+
3614
+	        if ($messagingProfileId != '') {
3615
+	            $messagingprofenc = $this->crypto->encrypt($messagingProfileId);             
3616
+	        } else { $messagingprofenc = ''; }
3617
+
3618
+	        if ($nexapiKey != '') {
3619
+	            $nexapikeystrenc = $this->crypto->encrypt($nexapiKey);             
3620
+	        } else { $nexapikeystrenc = ''; }
3621
+
3622
+	        if ($nexapiSecret != '') {
3623
+	            $nexapisecretstrenc = $this->crypto->encrypt($nexapiSecret);             
3624
+	        } else { $nexapisecretstrenc = ''; }
3625
+
3626
+	        if ($twilapiKey != '') {
3627
+	            $twilapikeystrenc = $this->crypto->encrypt($twilapiKey);             
3628
+	        } else { $twilapikeystrenc = ''; }
3629
+
3630
+	        if ($twilapiSecret != '') {
3631
+	            $twilapisecretstrenc = $this->crypto->encrypt($twilapiSecret);             
3632
+	        } else { $twilapisecretstrenc = ''; }
3633
+
3634
+	        if ($flowapiKey != '') {
3635
+	            $flowapikeystrenc = $this->crypto->encrypt($flowapiKey);             
3636
+	        } else { $flowapikeystrenc = ''; }
3637
+
3638
+	        if ($flowapiSecret != '') {
3639
+	            $flowapisecretstrenc = $this->crypto->encrypt($flowapiSecret);             
3640
+	        } else { $flowapisecretstrenc = ''; }
3641
+
3642
+
3643
+	        $sql = $this->connection->prepare('
3644
+				INSERT INTO `*PREFIX*sms_relent_settings`
3645
+					(`user_id`, `telapi_key`, `tel_pub_key`, `telapi_url_rec`, `telapi_url`, `messaging_profile_id`, `nexapi_key`, `nexapi_secret`, `nexapi_url_rec`, 
3646
+	                                 `nexapi_url`, `tel_sender_name`, `nex_sender_name`, `twilapi_key`, `twilapi_secret`, `twilapi_url_rec`, `twilapi_url`, `twil_sender_name`, 
3647
+                                         `flowapi_key`, `flowapi_secret`, `flowapi_url_rec`, `flowapi_url`, `show_all_messages`)
3648
+				VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
3649
+			');
3650
+	        $sql->execute([$userId, $telapikeystrenc, $telpubkeystrenc, $telapiUrlRec, $telapiUrl, $messagingprofenc, $nexapikeystrenc, $nexapisecretstrenc, $nexapiUrlRec, 
3651
+                               $nexapiUrl, $telSenderName, $nexSenderName, $twilapikeystrenc, $twilapisecretstrenc, $twilapiUrlRec, $twilapiUrl, $twilSenderName, $flowapikeystrenc, 
3652
+                               $flowapisecretstrenc, $flowapiUrlRec, $flowapiUrl, $showAllMessages]);
3653
+
3654
+            } elseif ($resultstng && $rowup) {
3655
+
3656
+	        // Check if the value of the field is the placeholder or an empty string
3657
+	        if ($telapiKey != '' && $telapiKey != "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20") {
3658
+	            $telapikeystrenc = $this->crypto->encrypt($telapiKey);                
3659
+	        } elseif ($telapiKey == "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20") {
3660
+	            $telapikeystrenc = $rowup['telapi_key'];
3661
+	        } elseif ($telapiKey == '') {
3662
+	            $telapikeystrenc = '';
3663
+	        }
3664
+
3665
+	        if ($telPubKey != '' && $telPubKey != "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20") {
3666
+	            $telpubkeystrenc = $this->crypto->encrypt($telPubKey);                
3667
+	        } elseif ($telPubKey == "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20") {
3668
+	            $telpubkeystrenc = $rowup['tel_pub_key'];
3669
+	        } elseif ($telPubKey == '') {
3670
+	            $telpubkeystrenc = '';
3671
+	        }
3672
+
3673
+	        if ($messagingProfileId != '' && $messagingProfileId != "%20%20%20%20%20%20%20%20%20%20%20%20") {
3674
+	            $messagingprofenc = $this->crypto->encrypt($messagingProfileId);                
3675
+	        } elseif ($messagingProfileId == "%20%20%20%20%20%20%20%20%20%20%20%20") {
3676
+	            $messagingprofenc = $rowup['messaging_profile_id'];
3677
+	        } elseif ($messagingProfileId == '') {
3678
+	            $messagingprofenc = '';
3679
+	        }
3680
+
3681
+	        if ($nexapiKey != '' && $nexapiKey != "%20%20%20%20%20%20%20%20%20") {
3682
+	            $nexapikeystrenc = $this->crypto->encrypt($nexapiKey);                
3683
+	        } elseif ($nexapiKey == "%20%20%20%20%20%20%20%20%20") {
3684
+	            $nexapikeystrenc = $rowup['nexapi_key'];
3685
+	        } elseif ($nexapiKey == '') {
3686
+	            $nexapikeystrenc = '';
3687
+	        }
3688
+
3689
+	        if ($twilapiKey != '' && $twilapiKey != "%20%20%20%20%20%20%20%20%20") {
3690
+	            $twilapikeystrenc = $this->crypto->encrypt($twilapiKey);                
3691
+	        } elseif ($twilapiKey == "%20%20%20%20%20%20%20%20%20") {
3692
+	            $twilapikeystrenc = $rowup['twilapi_key'];
3693
+	        } elseif ($twilapiKey == '') {
3694
+	            $twilapikeystrenc = '';
3695
+	        }
3696
+
3697
+	        if ($flowapiKey != '' && $flowapiKey != "%20%20%20%20%20%20%20%20%20") {
3698
+	            $flowapikeystrenc = $this->crypto->encrypt($flowapiKey);                
3699
+	        } elseif ($flowapiKey == "%20%20%20%20%20%20%20%20%20") {
3700
+	            $flowapikeystrenc = $rowup['flowapi_key'];
3701
+	        } elseif ($flowapiKey == '') {
3702
+	            $flowapikeystrenc = '';
3703
+	        }
3704
+
3705
+	        if ($nexapiSecret != '' && $nexapiSecret != "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20") {
3706
+	            $nexapisecretstrenc = $this->crypto->encrypt($nexapiSecret);                
3707
+	        } elseif ($nexapiSecret == "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20") {
3708
+	            $nexapisecretstrenc = $rowup['nexapi_secret'];
3709
+	        } elseif ($nexapiSecret == '') {
3710
+	            $nexapisecretstrenc = '';
3711
+	        }
3712
+
3713
+	        if ($twilapiSecret != '' && $twilapiSecret != "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20") {
3714
+	            $twilapisecretstrenc = $this->crypto->encrypt($twilapiSecret);                
3715
+	        } elseif ($twilapiSecret == "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20") {
3716
+	            $twilapisecretstrenc = $rowup['twilapi_secret'];
3717
+	        } elseif ($twilapiSecret == '') {
3718
+	            $twilapisecretstrenc = '';
3719
+	        }
3720
+
3721
+	        if ($flowapiSecret != '' && $flowapiSecret != "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20") {
3722
+	            $flowapisecretstrenc = $this->crypto->encrypt($flowapiSecret);                
3723
+	        } elseif ($flowapiSecret == "%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20") {
3724
+	            $flowapisecretstrenc = $rowup['flowapi_secret'];
3725
+	        } elseif ($flowapiSecret == '') {
3726
+	            $flowapisecretstrenc = '';
3727
+	        }
3728
+
3729
+	        $sqlupdatedb = $this->connection->prepare('
3730
+			UPDATE `*PREFIX*sms_relent_settings`
3731
+			SET `telapi_key` = ?, `tel_pub_key` = ?, `telapi_url_rec` = ?, `telapi_url` = ?, `messaging_profile_id` = ?, `nexapi_key` = ?, `nexapi_secret` = ?,
3732
+	                    `nexapi_url_rec` = ?, `nexapi_url` = ?, `tel_sender_name` = ?, `nex_sender_name` = ?, `twilapi_key` = ?, `twilapi_secret` = ?, `twilapi_url_rec` = ?, `twilapi_url` = ?, `twil_sender_name` = ?, `flowapi_key` = ?, 
3733
+	                    `flowapi_secret` = ?, `flowapi_url_rec` = ?, `flowapi_url` = ?, `show_all_messages` = ?
3734
+	                WHERE `user_id` = ?');
3735
+	        $updateRes = $sqlupdatedb->execute([$telapikeystrenc, $telpubkeystrenc, $telapiUrlRec, $telapiUrl, $messagingprofenc, $nexapikeystrenc, $nexapisecretstrenc, 
3736
+                                                    $nexapiUrlRec, $nexapiUrl, $telSenderName, $nexSenderName, $twilapikeystrenc, $twilapisecretstrenc, $twilapiUrlRec, $twilapiUrl, 
3737
+                                                    $twilSenderName, $flowapikeystrenc, $flowapisecretstrenc, $flowapiUrlRec, $flowapiUrl, $showAllMessages, $userId]);
3738
+	        $updateRes->closeCursor();
3739
+
3740
+	    }
3741
+        }
3742
+     }
3743
+
3744
+
3745
+     public function updatepersadmnsettings($userId, $messagesperpage, $getNotify, $notificationEmail, $getsmsinemail, $showDisplayNames, $addDisplayNames, $msgCheckInterval) {
3746
+
3747
+        if ($this->groupManager->isAdmin($userId)) {
3748
+
3749
+            $upsettings = $this->connection->prepare('
3750
+                        SELECT `id`, `user_id`, `telapi_key`, `tel_pub_key`, `telapi_url_rec`, `telapi_url`, `messaging_profile_id`, `nexapi_key`, `nexapi_secret`, `nexapi_url_rec`,
3751
+                           `nexapi_url`, `twilapi_key`, `twilapi_secret`, `twilapi_url_rec`, `twilapi_url`, `flowapi_key`, `flowapi_secret`, `flowapi_url_rec`, `flowapi_url`, 
3752
+                           `tel_sender_name`, `nex_sender_name`, `twil_sender_name`, `flow_sender_name`, `messagesperpage`, `get_notify`, `notification_email`, `getsmsinemail`, 
3753
+                           `show_all_messages`, `show_display_names`, `add_display_names`, `available_numbers`, `msg_check_interval`, `new_message_rcd`
3754
+		        FROM  `*PREFIX*sms_relent_settings`
3755
+		        WHERE `user_id` = ?');
3756
+
3757
+            $resultstng = $upsettings->execute([$userId]);
3758
+
3759
+            $rowup = $resultstng->fetch();
3760
+
3761
+            $resultstng->closeCursor();
3762
+
3763
+            if ($resultstng && !$rowup) {
3764
+
3765
+	        $sql = $this->connection->prepare('
3766
+				INSERT INTO `*PREFIX*sms_relent_settings` (`user_id`, `messagesperpage`, `get_notify`, `notification_email`, `getsmsinemail`, `show_display_names`,
3767
+                                `add_display_names`, `msg_check_interval`)
3768
+				VALUES (?, ?, ?, ?, ?, ?, ?, ?)');
3769
+	        $sql->execute([$userId, $messagesperpage, $getNotify, $notificationEmail, $getsmsinemail, $showDisplayNames, $addDisplayNames, $msgCheckInterval]);
3770
+
3771
+            } elseif ($resultstng && $rowup) {
3772
+
3773
+	        $sqlupdatedb = $this->connection->prepare('
3774
+			UPDATE `*PREFIX*sms_relent_settings`
3775
+			SET `messagesperpage` = ?, `get_notify` = ?, `notification_email` = ?, `getsmsinemail` = ?, `show_display_names` = ?, `add_display_names` = ?, 
3776
+                            `msg_check_interval` = ?
3777
+	                WHERE `user_id` = ?');
3778
+	        $updateRes = $sqlupdatedb->execute([$messagesperpage, $getNotify, $notificationEmail, $getsmsinemail, $showDisplayNames, $addDisplayNames, $msgCheckInterval, $userId]);
3779
+	        $updateRes->closeCursor();
3780
+            }
3781
+        }
3782
+     }
3783
+
3784
+
3785
+     /**
3786
+      * @NoAdminRequired
3787
+      */
3788
+     public function getapicredentials($userId) {
3789
+
3790
+        $sqlcr = $this->connection->prepare('
3791
+              SELECT `id`, `user_id`, `telapi_key`, `tel_pub_key`, `telapi_url_rec`, `telapi_url`, `messaging_profile_id`, `nexapi_key`, `nexapi_secret`, `nexapi_url_rec`, `nexapi_url`,
3792
+                     `tel_sender_name`, `nex_sender_name`, `messagesperpage`, `get_notify`, `notification_email`, `getsmsinemail`, `twilapi_key`, `twilapi_secret`, `twilapi_url_rec`, 
3793
+                     `twilapi_url`, `twil_sender_name`, `flowapi_key`, `flowapi_secret`, `flowapi_url_rec`, `flowapi_url`, `add_display_names` FROM `*PREFIX*sms_relent_settings`
3794
+	      WHERE `user_id` = ?');
3795
+	$resultcr = $sqlcr->execute([$userId]);
3796
+        $settingsfrdb = $resultcr->fetch();
3797
+        $resultcr->closeCursor();
3798
+
3799
+        if (($settingsfrdb['telapi_key'] != '') && ($settingsfrdb['telapi_key'] != 'undefined') && ($settingsfrdb['telapi_key'] != null)) { 
3800
+             $telapikeystrdec = $this->crypto->decrypt($settingsfrdb['telapi_key']); 
3801
+        } else { $telapikeystrdec = ''; }
3802
+
3803
+        if (($settingsfrdb['tel_pub_key'] != '') && ($settingsfrdb['tel_pub_key'] != 'undefined') && ($settingsfrdb['tel_pub_key'] != null)) {
3804
+             $telpubkeystrdec = $this->crypto->decrypt($settingsfrdb['tel_pub_key']); 
3805
+        } else { $telpubkeystrdec = ''; }
3806
+
3807
+        $telapiurlrec = $settingsfrdb['telapi_url_rec'];
3808
+        $telapiurlstr = $settingsfrdb['telapi_url'];
3809
+
3810
+        if (($settingsfrdb['messaging_profile_id'] != '') && ($settingsfrdb['messaging_profile_id'] != 'undefined') && ($settingsfrdb['messaging_profile_id'] != null)) {
3811
+             $messagingprofid = $this->crypto->decrypt($settingsfrdb['messaging_profile_id']); 
3812
+        } else { $messagingprofid = ''; }
3813
+
3814
+        if (($settingsfrdb['nexapi_key'] != '') && ($settingsfrdb['nexapi_key'] != 'undefined') && ($settingsfrdb['nexapi_key'] != null)) { 
3815
+             $nexapikeystr = $this->crypto->decrypt($settingsfrdb['nexapi_key']); 
3816
+        } else { $nexapikeystr = ''; }
3817
+
3818
+        if (($settingsfrdb['nexapi_secret'] != '') && ($settingsfrdb['nexapi_secret'] != 'undefined') && ($settingsfrdb['nexapi_secret'] != null)) { 
3819
+             $nexapisecretstr = $this->crypto->decrypt($settingsfrdb['nexapi_secret']); 
3820
+        } else { $nexapisecretstr = ''; }
3821
+
3822
+        if (($settingsfrdb['twilapi_key'] != '') && ($settingsfrdb['twilapi_key'] != 'undefined') && ($settingsfrdb['twilapi_key'] != null)) { 
3823
+             $twilapikeystr = $this->crypto->decrypt($settingsfrdb['twilapi_key']); 
3824
+        } else { $twilapikeystr = ''; }
3825
+
3826
+        if (($settingsfrdb['twilapi_secret'] != '') && ($settingsfrdb['twilapi_secret'] != 'undefined') && ($settingsfrdb['twilapi_secret'] != null)) { 
3827
+             $twilapisecretstr = $this->crypto->decrypt($settingsfrdb['twilapi_secret']); 
3828
+        } else { $twilapisecretstr = ''; }
3829
+
3830
+        if (($settingsfrdb['flowapi_key'] != '') && ($settingsfrdb['flowapi_key'] != 'undefined') && ($settingsfrdb['flowapi_key'] != null)) { 
3831
+             $flowapikeystr = $this->crypto->decrypt($settingsfrdb['flowapi_key']); 
3832
+        } else { $flowapikeystr = ''; }
3833
+
3834
+        if (($settingsfrdb['flowapi_secret'] != '') && ($settingsfrdb['flowapi_secret'] != 'undefined') && ($settingsfrdb['flowapi_secret'] != null)) { 
3835
+             $flowapisecretstr = $this->crypto->decrypt($settingsfrdb['flowapi_secret']); 
3836
+        } else { $flowapisecretstr = ''; }
3837
+
3838
+        $nexapiurlrecsms = $settingsfrdb['nexapi_url_rec'];
3839
+        $nexapiurldelrcpt = $settingsfrdb['nexapi_url'];
3840
+        $twilapiurlrecsms = $settingsfrdb['twilapi_url_rec'];
3841
+        $twilapiurldelrcpt = $settingsfrdb['twilapi_url'];
3842
+        $flowapiurlrecsms = $settingsfrdb['flowapi_url_rec'];
3843
+        $flowapiurldelrcpt = $settingsfrdb['flowapi_url'];
3844
+        $gettelsendername = $settingsfrdb['tel_sender_name'];
3845
+        $getnexsendername = $settingsfrdb['nex_sender_name'];
3846
+        $gettwilsendername = $settingsfrdb['twil_sender_name'];
3847
+        $getmessagesperpage = $settingsfrdb['messagesperpage'];
3848
+        $getnotification = $settingsfrdb['get_notify'];
3849
+        $notifyemail = $settingsfrdb['notification_email'];
3850
+        $includesmsinemail = $settingsfrdb['getsmsinemail'];
3851
+        $includeDisplNames = $settingsfrdb['add_display_names'];
3852
+
3853
+        return [$telapikeystrdec, $telpubkeystrdec, $telapiurlrec, $telapiurlstr, $messagingprofid, $nexapikeystr, $nexapisecretstr, $nexapiurlrecsms, $nexapiurldelrcpt,
3854
+                $gettelsendername, $getnexsendername, $getmessagesperpage, $getnotification, $notifyemail, $includesmsinemail, $twilapikeystr, $twilapisecretstr, $twilapiurlrecsms, 
3855
+                $twilapiurldelrcpt, $gettwilsendername, $flowapikeystr, $flowapisecretstr, $flowapiurlrecsms, $flowapiurldelrcpt, $includeDisplNames];
3856
+     }
3857
+
3858
+     /**
3859
+      * @NoAdminRequired
3860
+      */
3861
+     public function getuserbytelrecwhurl($recsmswebhookurl) {
3862
+
3863
+        $sqlrec = $this->connection->prepare('SELECT `user_id`, `telapi_url_rec` FROM `*PREFIX*sms_relent_settings` WHERE `telapi_url_rec` = ?');
3864
+	$result = $sqlrec->execute([$recsmswebhookurl]);
3865
+        $datafromdb = $result->fetch();
3866
+        $result->closeCursor();
3867
+        $ncusertelrec = $datafromdb['user_id'];
3868
+
3869
+        return $ncusertelrec;
3870
+     }
3871
+
3872
+     /**
3873
+      * @NoAdminRequired
3874
+      */
3875
+     public function getuserbyteldelrwhurl($delsmswebhookurl) {
3876
+
3877
+        $sqldel = $this->connection->prepare('SELECT `user_id`, `telapi_url` FROM `*PREFIX*sms_relent_settings` WHERE `telapi_url` = ?');
3878
+	$ressqldel = $sqldel->execute([$delsmswebhookurl]);
3879
+        $datafromdbdel = $ressqldel->fetch();
3880
+        $ressqldel->closeCursor();
3881
+        $ncuserteldel = $datafromdbdel['user_id'];
3882
+
3883
+        return $ncuserteldel;
3884
+     }
3885
+
3886
+     /**
3887
+      * @NoAdminRequired
3888
+      */
3889
+     public function getuserbyplivorecwhurl($plivorecurl) {
3890
+
3891
+        $sqlrecpl = $this->connection->prepare('SELECT `user_id`, `nexapi_url_rec` FROM `*PREFIX*sms_relent_settings` WHERE `nexapi_url_rec` = ?');
3892
+	$plresrecsql = $sqlrecpl->execute([$plivorecurl]);
3893
+        $pldatafromdb = $plresrecsql->fetch();
3894
+        $plresrecsql->closeCursor();
3895
+        $ncuserplrec = $pldatafromdb['user_id'];
3896
+
3897
+        return $ncuserplrec;
3898
+     }
3899
+
3900
+     /**
3901
+      * @NoAdminRequired
3902
+      */
3903
+     public function getuserbyplivodelrwhurl($plivodrurl) {
3904
+
3905
+        $sqldrpl = $this->connection->prepare('SELECT `user_id`, `nexapi_url` FROM `*PREFIX*sms_relent_settings` WHERE `nexapi_url` = ?');
3906
+	$ressqldelrec = $sqldrpl->execute([$plivodrurl]);
3907
+        $datafromdbdr = $ressqldelrec->fetch();
3908
+        $ressqldelrec->closeCursor();
3909
+        $ncuserplivodel = $datafromdbdr['user_id'];
3910
+
3911
+        return $ncuserplivodel;
3912
+     }
3913
+
3914
+     /**
3915
+      * @NoAdminRequired
3916
+      */
3917
+     public function getuserbytwilrecwhurl($twilrecurl) {
3918
+
3919
+        $sqlrectw = $this->connection->prepare('SELECT `user_id`, `twilapi_url_rec` FROM `*PREFIX*sms_relent_settings` WHERE `twilapi_url_rec` = ?');
3920
+	$twresrecsql = $sqlrectw->execute([$twilrecurl]);
3921
+        $twdatafromdb = $twresrecsql->fetch();
3922
+        $twresrecsql->closeCursor();
3923
+        $ncusertwrec = $twdatafromdb['user_id'];
3924
+
3925
+        return $ncusertwrec;
3926
+     }
3927
+
3928
+     /**
3929
+      * @NoAdminRequired
3930
+      */
3931
+     public function getuserbytwildelrwhurl($twildrurl) {
3932
+
3933
+        $sqldrtw = $this->connection->prepare('SELECT `user_id`, `twilapi_url` FROM `*PREFIX*sms_relent_settings` WHERE `twilapi_url` = ?');
3934
+	$ressqldelrectw = $sqldrtw->execute([$twildrurl]);
3935
+        $datafromdbdrtw = $ressqldelrectw->fetch();
3936
+        $ressqldelrectw->closeCursor();
3937
+        $ncusertwildel = $datafromdbdrtw['user_id'];
3938
+
3939
+        return $ncusertwildel;
3940
+     }
3941
+
3942
+     /**
3943
+      * @NoAdminRequired
3944
+      */
3945
+     public function getuserbyflowrecwhurl($flowrecurl) {
3946
+
3947
+        $sqlrecfl = $this->connection->prepare('SELECT `user_id`, `flowapi_url_rec` FROM `*PREFIX*sms_relent_settings` WHERE `flowapi_url_rec` = ?');
3948
+	$flresrecsql = $sqlrecfl->execute([$flowrecurl]);
3949
+        $fldatafromdb = $flresrecsql->fetch();
3950
+        $flresrecsql->closeCursor();
3951
+        $ncuserflrec = $fldatafromdb['user_id'];
3952
+
3953
+        return $ncuserflrec;
3954
+     }
3955
+
3956
+     /**
3957
+      * @NoAdminRequired
3958
+      */
3959
+     public function getuserbyflowdelrwhurl($flowdrurl) {
3960
+
3961
+        $sqldrfl = $this->connection->prepare('SELECT `user_id`, `flowapi_url` FROM `*PREFIX*sms_relent_settings` WHERE `flowapi_url` = ?');
3962
+	$ressqldelrecfl = $sqldrfl->execute([$flowdrurl]);
3963
+        $datafromdbdrfl = $ressqldelrecfl->fetch();
3964
+        $ressqldelrecfl->closeCursor();
3965
+        $ncuserflowdel = $datafromdbdrfl['user_id'];
3966
+
3967
+        return $ncuserflowdel;
3968
+     }
3969
+
3970
+
3971
+    /**
3972
+     * @NoAdminRequired
3973
+     */
3974
+    public function object_to_array($obj) {
3975
+        if (is_object($obj)) $obj = (array)$this->dismount($obj);
3976
+        if (is_array($obj)) {
3977
+           $new = array();
3978
+           foreach($obj as $key => $val) {
3979
+               $new[$key] = $this->object_to_array($val);
3980
+           }
3981
+        }
3982
+        else $new = $obj;
3983
+        return $new;
3984
+    }
3985
+
3986
+
3987
+    /**
3988
+     * @NoAdminRequired
3989
+     */
3990
+    public function dismount($object) {
3991
+        $reflectionClass = new ReflectionClass(get_class($object));
3992
+        $array = array();
3993
+        foreach ($reflectionClass->getProperties() as $property) {
3994
+           $property->setAccessible(true);
3995
+           $array[$property->getName()] = $property->getValue($object);
3996
+           $property->setAccessible(false);
3997
+        }
3998
+        return $array;
3999
+    }
4000
+
4001
+
4002
+    /**
4003
+     * @NoAdminRequired
4004
+     */
4005
+    public function getallowedusers($userId) {
4006
+
4007
+        // Collect the users with whom the current admin is sharing his API keys and whose messages he will be able to see
4008
+        if ($this->groupManager->isAdmin($userId)) {
4009
+
4010
+            // Get the groups and users that were allowed access to the API keys
4011
+            $getgrps = $this->connection->prepare('SELECT `user_id`, `tnx_groups_allowed`, `tnx_users_allowed`, `plv_groups_allowed`, `plv_users_allowed`,
4012
+                                                  `twl_groups_allowed`, `twl_users_allowed`, `flr_groups_allowed`, `flr_users_allowed` FROM `*PREFIX*sms_relent_subac`
4013
+                                                   WHERE `user_id` = ?');
4014
+            $getgrpsres = $getgrps->execute([$userId]);
4015
+            $getgrpsusr = $getgrpsres->fetch();
4016
+            $getgrpsres->closeCursor();
4017
+
4018
+            if ($getgrpsusr) {
4019
+
4020
+                if ($getgrpsusr['tnx_users_allowed']) { $tnxusers = explode("|", $getgrpsusr['tnx_users_allowed']); } else { $tnxusers = []; }
4021
+                if ($getgrpsusr['plv_users_allowed']) { $plvusers = explode("|", $getgrpsusr['plv_users_allowed']); } else { $plvusers = []; }
4022
+                if ($getgrpsusr['twl_users_allowed']) { $twlusers = explode("|", $getgrpsusr['twl_users_allowed']); } else { $twlusers = []; }
4023
+                if ($getgrpsusr['flr_users_allowed']) { $flrusers = explode("|", $getgrpsusr['flr_users_allowed']); } else { $flrusers = []; }
4024
+
4025
+                $allwdusersarr = array_merge($tnxusers, $plvusers, $twlusers, $flrusers);
4026
+                $allwdusersunq = array_filter(array_unique($allwdusersarr));
4027
+
4028
+                if ($getgrpsusr['tnx_groups_allowed']) { $tnxgroups = explode("|", $getgrpsusr['tnx_groups_allowed']); } else { $tnxgroups = []; }
4029
+                if ($getgrpsusr['plv_groups_allowed']) { $plvgroups = explode("|", $getgrpsusr['plv_groups_allowed']); } else { $plvgroups = []; }
4030
+                if ($getgrpsusr['twl_groups_allowed']) { $twlgroups = explode("|", $getgrpsusr['twl_groups_allowed']); } else { $twlgroups = []; }
4031
+                if ($getgrpsusr['flr_groups_allowed']) { $flrgroups = explode("|", $getgrpsusr['flr_groups_allowed']); } else { $flrgroups = []; }
4032
+
4033
+                $allwdgroupsarr = array_merge($tnxgroups, $plvgroups, $twlgroups, $flrgroups);
4034
+                $allwdgroupsunq = array_filter(array_unique($allwdgroupsarr));
4035
+
4036
+            } else {
4037
+                $allwdusersunq = [];
4038
+                $allwdgroupsunq = [];
4039
+            }
4040
+
4041
+            // Get the username for each Display Name of the allowed users
4042
+            $allwdusersfnl = [];
4043
+            foreach ($allwdusersunq as $alwdusrkey => $alwdusrvalue) {
4044
+
4045
+                         $getacdatausrnm = $this->connection->prepare('SELECT `uid`, `name`, `value` FROM `*PREFIX*accounts_data` WHERE `name` = ? AND `value` = ?');
4046
+		         $getacdatausrnmres = $getacdatausrnm->execute(['displayname', $alwdusrvalue]);
4047
+		         $acdatausrname = $getacdatausrnmres->fetch();
4048
+                         if ($acdatausrname) {
4049
+                             $allwdusersfnl[] = $acdatausrname['uid'];
4050
+                         }
4051
+                         $getacdatausrnmres->closeCursor();
4052
+            }
4053
+
4054
+            // Get the users from all the allowed groups
4055
+            $allwdusersgrpmlt = [];
4056
+            foreach ($allwdgroupsunq as $prgrpkey => $prgrpvalue) {
4057
+
4058
+                     // Get all the users that belong to the current group, if the current group is different from 'admin'
4059
+                     if ($prgrpvalue != 'admin') {
4060
+                         $getusringroup = $this->connection->prepare('SELECT `gid`, `uid` FROM `*PREFIX*group_user` WHERE `gid` = ?');
4061
+		         $getusringroupres = $getusringroup->execute([$prgrpvalue]);
4062
+
4063
+		         while ($getusrname = $getusringroupres->fetch()) {
4064
+
4065
+                                $allwdusersgrpmlt[] = $getusrname['uid'];
4066
+                         }
4067
+		         $getusringroupres->closeCursor();
4068
+                     }
4069
+            }
4070
+            $allwdusersgrpfnl = array_unique($allwdusersgrpmlt);
4071
+            
4072
+            $allusr = array_merge($allwdusersfnl, $allwdusersgrpfnl);
4073
+            $allusruniquest = array_unique($allusr);
4074
+
4075
+            if ($allusruniquest) {
4076
+                array_unshift($allusruniquest, $userId);
4077
+                $allusruniquerc = $allusruniquest;
4078
+            } else { $allusruniquerc = [$userId]; }
4079
+
4080
+            return $allusruniquerc;
4081
+
4082
+        } else { return [$userId]; }
4083
+    }
4084
+
4085
+
4086
+    /**
4087
+     * @NoAdminRequired
4088
+     */
4089
+    public function getsmsnumbers($userId) {
4090
+
4091
+        // Check if there are any saved phone numbers for the current user
4092
+        $getnumbers = $this->connection->prepare('SELECT `user_id`, `available_numbers` FROM `*PREFIX*sms_relent_settings` WHERE `user_id` = ?');
4093
+	$getcrtusrno = $getnumbers->execute([$userId]);
4094
+        $getusrnmbrs = $getcrtusrno->fetch();
4095
+        $getcrtusrno->closeCursor();
4096
+
4097
+        if ($getusrnmbrs['available_numbers']) {
4098
+
4099
+            $retrievednmbrs = $getusrnmbrs['available_numbers'];
4100
+            $getnmbrsarr = explode("|", $retrievednmbrs);
4101
+            $numbersforuser = array_filter($getnmbrsarr);
4102
+            return $numbersforuser;
4103
+
4104
+        // Get the available phone numbers for the current user from the SMS providers
4105
+        } else {
4106
+
4107
+            $smsapicred = $this->getapicredentials($userId);
4108
+
4109
+            $telnyxkey = $smsapicred[0];
4110
+
4111
+            $nexapikey = $smsapicred[5];
4112
+            $nexapisecret = $smsapicred[6];
4113
+
4114
+            $twilapikey = $smsapicred[15];
4115
+            $twilapisecret = $smsapicred[16];
4116
+
4117
+            $flowapikey = $smsapicred[20];
4118
+            $flowapisecret = $smsapicred[21];
4119
+
4120
+            $telsendernameinit = $smsapicred[9];
4121
+            $nexsendernameinit = $smsapicred[10];
4122
+            $twilsendernameinit = $smsapicred[19];
4123
+
4124
+            if ($telsendernameinit) {
4125
+                $telsendername = "Tx: " . $telsendernameinit;
4126
+                $telsenderarr = [0 => $telsendername];
4127
+            } else { $telsenderarr = []; }
4128
+
4129
+            if ($nexsendernameinit) {
4130
+                $nexsendername = "Pl: " . $nexsendernameinit;
4131
+                $nexsenderarr = [0 => $nexsendername];
4132
+            } else { $nexsenderarr = []; }
4133
+
4134
+            if ($twilsendernameinit) {
4135
+                $twilsendername = "Tw: " . $twilsendernameinit;
4136
+                $twilsenderarr = [0 => $twilsendername];
4137
+            } else { $twilsenderarr = []; }
4138
+
4139
+            // Get Telnyx phone numbers
4140
+            if ($telnyxkey != '') {
4141
+
4142
+               \Telnyx\Telnyx::setApiKey($telnyxkey);
4143
+               $telnumbers = \Telnyx\MessagingPhoneNumber::All();
4144
+
4145
+               $telnumbersarr = $this->object_to_array($telnumbers);
4146
+               $telnmbrs = [];
4147
+
4148
+               foreach ($telnumbersarr['_originalValues'] as $nmbkey => $nmbvalue) {
4149
+                   if (is_int($nmbkey)) {
4150
+                       foreach ($nmbvalue as $nkey => $nvalue) {
4151
+                           if ($nkey == 'phone_number' && $nvalue) {
4152
+                               $telnmbrs[] = "Tx: " . $nvalue;
4153
+                           }
4154
+                       }
4155
+                   }
4156
+               }
4157
+
4158
+            } else { $telnmbrs = []; }
4159
+
4160
+            // Get Plivo phone numbers
4161
+            if ($nexapikey != '' && $nexapisecret != '') {
4162
+
4163
+               $getacdata = "https://".$nexapikey.":".$nexapisecret."@api.plivo.com/v1/Account/".$nexapikey."/Number/";
4164
+               $acdata = file_get_contents($getacdata);
4165
+               $datainit = json_decode($acdata, true);
4166
+
4167
+               $findata = $this->object_to_array($datainit);
4168
+
4169
+               $nexcurrentnmbrs = [];
4170
+
4171
+               foreach ($findata['objects'] as $smskey => $smsvalue) {
4172
+                       if (is_array($smsvalue)) {
4173
+                             foreach ($smsvalue as $smskey2 => $smsvalue2) {
4174
+                                   if ($smskey2 == 'number' && $smsvalue2) {
4175
+                                       $nexcurrentnmbrs[] = "Pl: +" . $smsvalue2;
4176
+                                   }
4177
+                             }
4178
+                       }
4179
+               }
4180
+
4181
+            } else { $nexcurrentnmbrs = []; }
4182
+
4183
+            // Get Twilio phone numbers
4184
+            if ($twilapikey != '' && $twilapisecret != '') {
4185
+
4186
+                $twilnumbers = json_decode(file_get_contents("https://".$twilapikey.":".$twilapisecret."@api.twilio.com/2010-04-01/Accounts/".$twilapikey."/IncomingPhoneNumbers.json"), true);
4187
+                $twilactivenmbrs = $twilnumbers['incoming_phone_numbers'];
4188
+
4189
+                $twilcurrentnmbrs = [];
4190
+                foreach ($twilactivenmbrs as $twnbkey => $twnbvalue) {
4191
+                     if (is_array($twnbvalue)) {
4192
+                         foreach ($twnbvalue as $twfkey => $twfvalue) {
4193
+                              if ($twfkey == 'phone_number' && $twfvalue) {
4194
+                                  $twilcurrentnmbrs[] = "Tw: " . $twfvalue;
4195
+                              }
4196
+                         }
4197
+                     }
4198
+                }
4199
+
4200
+            } else { $twilcurrentnmbrs = []; }
4201
+
4202
+            // Get Flowroute phone numbers
4203
+            if ($flowapikey != '' && $flowapisecret != '') {
4204
+
4205
+                $flnbrsresult = json_decode(file_get_contents("https://".$flowapikey.":".$flowapisecret."@api.flowroute.com/v2/numbers"));
4206
+                $flnbrsarr = $flnbrsresult->data;
4207
+                $flowcurrentnmbrs = [];
4208
+                foreach ($flnbrsarr as $flkey => $flitem) {
4209
+                         if ($flitem->id) {
4210
+                             $flowcurrentnmbrs[] = "Fl: +" . $flitem->id;
4211
+                         }
4212
+                }
4213
+
4214
+            } else { $flowcurrentnmbrs = []; }
4215
+
4216
+            $currentnmbrs = array_merge($telnmbrs, $nexcurrentnmbrs, $twilcurrentnmbrs, $flowcurrentnmbrs, $telsenderarr, $nexsenderarr, $twilsenderarr);
4217
+
4218
+            if ($this->groupManager->isAdmin($userId)) {
4219
+
4220
+                // Save the available phone numbers for the current user
4221
+                $availablenmbrs = implode("|", $currentnmbrs);
4222
+                $savephno = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_settings` SET `available_numbers` = ? WHERE `user_id` = ?');
4223
+                $upusrphnmbrs = $savephno->execute([$availablenmbrs, $userId]);
4224
+	        $upusrphnmbrs->closeCursor();
4225
+
4226
+                return $currentnmbrs;
4227
+
4228
+            } else {
4229
+
4230
+                // Get the restrictions from the 'sms_relent_restrict' table
4231
+                $getrestr = $this->connection->prepare('
4232
+		            SELECT `phone_number`, `groups`, `users` FROM `*PREFIX*sms_relent_restrict`');
4233
+                $getrestrres = $getrestr->execute();
4234
+
4235
+                $restrdata = [];
4236
+                while ($restrfetched = $getrestrres->fetch()) {
4237
+                       $restrdata[] = $restrfetched;
4238
+                }
4239
+                $getrestrres->closeCursor();
4240
+
4241
+                if ($restrdata) {
4242
+
4243
+                    // Get the groups to which the current user belongs
4244
+                    $getusrgrp = $this->connection->prepare('
4245
+		                 SELECT `gid`, `uid` FROM `*PREFIX*group_user` WHERE `uid` = ?');
4246
+                    $getusrgrpres = $getusrgrp->execute([$userId]);
4247
+
4248
+                    $usergrps = [];
4249
+                    while ($fetchedgrps = $getusrgrpres->fetch()) {
4250
+                           $usergrps[] = $fetchedgrps['gid'];
4251
+                    }
4252
+                    $getusrgrpres->closeCursor();
4253
+                    $ctusergroups = implode("|", $usergrps);
4254
+
4255
+		    // Get the Display Name of the current user
4256
+		    $getacdatadn = $this->connection->prepare('SELECT `uid`, `name`, `value` FROM `*PREFIX*accounts_data` WHERE `uid` = ? AND `name` = ?');
4257
+		    $getacdatadnres = $getacdatadn->execute([$userId, 'displayname']);
4258
+		    $acdatausrdnadm = $getacdatadnres->fetch();
4259
+		    $cruserdname = $acdatausrdnadm['value'];
4260
+		    $getacdatadnres->closeCursor();
4261
+
4262
+                    // Get the phone numbers that are not allowed for the current user
4263
+                    $restrPhoneNb = [];
4264
+                    foreach ($restrdata as $rskey => $rsvalue) {
4265
+
4266
+                        $chck = 0;
4267
+                        if ($rsvalue['groups']) {
4268
+                            $restrgrparr = explode("|", $rsvalue['groups']);
4269
+
4270
+                            foreach ($restrgrparr as $grkey => $grvalue) {
4271
+                                     if (str_contains($ctusergroups, $grvalue)) { $chck++; }
4272
+                            }
4273
+                        }
4274
+
4275
+                        if ($rsvalue['users']) {
4276
+                            $usrnmstr = $rsvalue['users'];
4277
+                            if (str_contains($usrnmstr, $cruserdname)) { $chck++; }
4278
+                        }
4279
+
4280
+                        if ($chck == 0) { $restrPhoneNb[] = $rsvalue['phone_number']; }
4281
+                    }
4282
+
4283
+                    $restrPhoneNmbrs = array_unique($restrPhoneNb);
4284
+
4285
+                    // Assemble the array of phone numbers that the current user is allowed to use
4286
+                    for ($k = 0; $k < count($currentnmbrs); $k++) {
4287
+
4288
+                        if (in_array($currentnmbrs[$k], $restrPhoneNmbrs)) {
4289
+                            unset($currentnmbrs[$k]);
4290
+                        }
4291
+                    }
4292
+
4293
+                    $currentnmbrsrstr = array_values($currentnmbrs);
4294
+
4295
+                    // Save the available phone numbers for the current user
4296
+                    $availablenmbrs = implode("|", $currentnmbrsrstr);
4297
+                    $savephno = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_settings` SET `available_numbers` = ? WHERE `user_id` = ?');
4298
+                    $upusrphnmbrs = $savephno->execute([$availablenmbrs, $userId]);
4299
+	            $upusrphnmbrs->closeCursor();
4300
+
4301
+                    return $currentnmbrsrstr;
4302
+
4303
+                } else {
4304
+
4305
+                    // Save the available phone numbers for the current user
4306
+                    $availablenmbrs = implode("|", $currentnmbrs);
4307
+                    $savephno = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_settings` SET `available_numbers` = ? WHERE `user_id` = ?');
4308
+                    $upusrphnmbrs = $savephno->execute([$availablenmbrs, $userId]);
4309
+	            $upusrphnmbrs->closeCursor();
4310
+
4311
+                    return $currentnmbrs; 
4312
+                }
4313
+            }
4314
+        }
4315
+    }
4316
+
4317
+
4318
+    /**
4319
+     * @NoAdminRequired
4320
+     */
4321
+    public function refreshavailablenumbers($userId) {
4322
+
4323
+        $smsapicred = $this->getapicredentials($userId);
4324
+
4325
+        $telnyxkey = $smsapicred[0];
4326
+
4327
+        $nexapikey = $smsapicred[5];
4328
+        $nexapisecret = $smsapicred[6];
4329
+
4330
+        $twilapikey = $smsapicred[15];
4331
+        $twilapisecret = $smsapicred[16];
4332
+
4333
+        $flowapikey = $smsapicred[20];
4334
+        $flowapisecret = $smsapicred[21];
4335
+
4336
+        $telsendernameinit = $smsapicred[9];
4337
+        $nexsendernameinit = $smsapicred[10];
4338
+        $twilsendernameinit = $smsapicred[19];
4339
+
4340
+        if ($telsendernameinit) {
4341
+            $telsendername = "Tx: " . $telsendernameinit;
4342
+            $telsenderarr = [0 => $telsendername];
4343
+        } else { $telsenderarr = []; }
4344
+
4345
+        if ($nexsendernameinit) {
4346
+            $nexsendername = "Pl: " . $nexsendernameinit;
4347
+            $nexsenderarr = [0 => $nexsendername];
4348
+        } else { $nexsenderarr = []; }
4349
+
4350
+        if ($twilsendernameinit) {
4351
+            $twilsendername = "Tw: " . $twilsendernameinit;
4352
+            $twilsenderarr = [0 => $twilsendername];
4353
+        } else { $twilsenderarr = []; }
4354
+
4355
+        // Get Telnyx phone numbers
4356
+        if ($telnyxkey != '') {
4357
+
4358
+           \Telnyx\Telnyx::setApiKey($telnyxkey);
4359
+           $telnumbers = \Telnyx\MessagingPhoneNumber::All();
4360
+
4361
+           $telnumbersarr = $this->object_to_array($telnumbers);
4362
+           $telnmbrs = [];
4363
+
4364
+           foreach ($telnumbersarr['_originalValues'] as $nmbkey => $nmbvalue) {
4365
+              if (is_int($nmbkey)) {
4366
+                 foreach ($nmbvalue as $nkey => $nvalue) {
4367
+                    if ($nkey == 'phone_number' && $nvalue) {
4368
+                       $telnmbrs[] = "Tx: " . $nvalue;
4369
+                    }
4370
+                 }
4371
+              }
4372
+           }
4373
+
4374
+        } else { $telnmbrs = []; }
4375
+
4376
+        // Get Plivo phone numbers
4377
+        if ($nexapikey != '' && $nexapisecret != '') {
4378
+
4379
+           $getacdata = "https://".$nexapikey.":".$nexapisecret."@api.plivo.com/v1/Account/".$nexapikey."/Number/";
4380
+           $acdata = file_get_contents($getacdata);
4381
+           $datainit = json_decode($acdata, true);
4382
+
4383
+           $findata = $this->object_to_array($datainit);
4384
+
4385
+           $nexcurrentnmbrs = [];
4386
+
4387
+           foreach ($findata['objects'] as $smskey => $smsvalue) {
4388
+                   if (is_array($smsvalue)) {
4389
+                         foreach ($smsvalue as $smskey2 => $smsvalue2) {
4390
+                               if ($smskey2 == 'number' && $smsvalue2) {
4391
+                                   $nexcurrentnmbrs[] = "Pl: +" . $smsvalue2;
4392
+                               }
4393
+                         }
4394
+                   }
4395
+           }
4396
+
4397
+        } else { $nexcurrentnmbrs = []; }
4398
+
4399
+        // Get Twilio phone numbers
4400
+        if ($twilapikey != '' && $twilapisecret != '') {
4401
+
4402
+            $twilnumbers = json_decode(file_get_contents("https://".$twilapikey.":".$twilapisecret."@api.twilio.com/2010-04-01/Accounts/".$twilapikey."/IncomingPhoneNumbers.json"), true);
4403
+            $twilactivenmbrs = $twilnumbers['incoming_phone_numbers'];
4404
+
4405
+            $twilcurrentnmbrs = [];
4406
+            foreach ($twilactivenmbrs as $twnbkey => $twnbvalue) {
4407
+                 if (is_array($twnbvalue)) {
4408
+                     foreach ($twnbvalue as $twfkey => $twfvalue) {
4409
+                          if ($twfkey == 'phone_number' && $twfvalue) {
4410
+                              $twilcurrentnmbrs[] = "Tw: " . $twfvalue;
4411
+                          }
4412
+                     }
4413
+                 }
4414
+            }
4415
+
4416
+        } else { $twilcurrentnmbrs = []; }
4417
+
4418
+        // Get Flowroute phone numbers
4419
+        if ($flowapikey != '' && $flowapisecret != '') {
4420
+
4421
+            $flnbrsresult = json_decode(file_get_contents("https://".$flowapikey.":".$flowapisecret."@api.flowroute.com/v2/numbers"));
4422
+            $flnbrsarr = $flnbrsresult->data;
4423
+            $flowcurrentnmbrs = [];
4424
+            foreach ($flnbrsarr as $flkey => $flitem) {
4425
+                     if ($flitem->id) {
4426
+                         $flowcurrentnmbrs[] = "Fl: +" . $flitem->id;
4427
+                     }
4428
+            }
4429
+
4430
+        } else { $flowcurrentnmbrs = []; }
4431
+
4432
+        $currentnmbrs = array_merge($telnmbrs, $nexcurrentnmbrs, $twilcurrentnmbrs, $flowcurrentnmbrs, $telsenderarr, $nexsenderarr, $twilsenderarr);
4433
+
4434
+
4435
+        if ($this->groupManager->isAdmin($userId)) {
4436
+
4437
+            // Save the available phone numbers for the current user
4438
+            $availablenmbrs = implode("|", $currentnmbrs);
4439
+            $savephno = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_settings` SET `available_numbers` = ? WHERE `user_id` = ?');
4440
+            $upusrphnmbrs = $savephno->execute([$availablenmbrs, $userId]);
4441
+	    $upusrphnmbrs->closeCursor();
4442
+
4443
+            return $currentnmbrs;
4444
+
4445
+        } else {
4446
+
4447
+            // Get the restrictions from the 'sms_relent_restrict' table
4448
+            $getrestr = $this->connection->prepare('
4449
+		       SELECT `phone_number`, `groups`, `users` FROM `*PREFIX*sms_relent_restrict`');
4450
+            $getrestrres = $getrestr->execute();
4451
+
4452
+            $restrdata = [];
4453
+            while ($restrfetched = $getrestrres->fetch()) {
4454
+                   $restrdata[] = $restrfetched;
4455
+            }
4456
+            $getrestrres->closeCursor();
4457
+
4458
+            if ($restrdata) {
4459
+
4460
+                // Get the groups to which the current user belongs
4461
+                $getusrgrp = $this->connection->prepare('
4462
+		       SELECT `gid`, `uid` FROM `*PREFIX*group_user` WHERE `uid` = ?');
4463
+                $getusrgrpres = $getusrgrp->execute([$userId]);
4464
+
4465
+                $usergrps = [];
4466
+                while ($fetchedgrps = $getusrgrpres->fetch()) {
4467
+                       $usergrps[] = $fetchedgrps['gid'];
4468
+                }
4469
+                $getusrgrpres->closeCursor();
4470
+                $ctusergroups = implode("|", $usergrps);
4471
+
4472
+		// Get the Display Name of the current user
4473
+		$getacdatadn = $this->connection->prepare('SELECT `uid`, `name`, `value` FROM `*PREFIX*accounts_data` WHERE `uid` = ? AND `name` = ?');
4474
+		$getacdatadnres = $getacdatadn->execute([$userId, 'displayname']);
4475
+		$acdatausrdnadm = $getacdatadnres->fetch();
4476
+		$cruserdname = $acdatausrdnadm['value'];
4477
+		$getacdatadnres->closeCursor();
4478
+
4479
+                // Get the phone numbers that are not allowed for the current user
4480
+                $restrPhoneNb = [];
4481
+                foreach ($restrdata as $rskey => $rsvalue) {
4482
+
4483
+                        $chck = 0;
4484
+                        if ($rsvalue['groups']) {
4485
+                            $restrgrparr = explode("|", $rsvalue['groups']);
4486
+
4487
+                            foreach ($restrgrparr as $grkey => $grvalue) {
4488
+                                     if (str_contains($ctusergroups, $grvalue)) { $chck++; }
4489
+                            }
4490
+                        }
4491
+
4492
+                        if ($rsvalue['users']) {
4493
+                            $usrnmstr = $rsvalue['users'];
4494
+                            if (str_contains($usrnmstr, $cruserdname)) { $chck++; }
4495
+                        }
4496
+
4497
+                        if ($chck == 0) { $restrPhoneNb[] = $rsvalue['phone_number']; }
4498
+                }
4499
+
4500
+                $restrPhoneNmbrs = array_unique($restrPhoneNb);
4501
+
4502
+                // Assemble the array of phone numbers that the current user is allowed to use
4503
+                for ($k = 0; $k < count($currentnmbrs); $k++) {
4504
+
4505
+                    if (in_array($currentnmbrs[$k], $restrPhoneNmbrs)) {
4506
+                        unset($currentnmbrs[$k]);
4507
+                    }
4508
+                }
4509
+
4510
+                $currentnmbrsrstr = array_values($currentnmbrs);
4511
+
4512
+                // Save the available phone numbers for the current user
4513
+                $availablenmbrs = implode("|", $currentnmbrsrstr);
4514
+                $savephno = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_settings` SET `available_numbers` = ? WHERE `user_id` = ?');
4515
+                $upusrphnmbrs = $savephno->execute([$availablenmbrs, $userId]);
4516
+	        $upusrphnmbrs->closeCursor();
4517
+
4518
+                return $currentnmbrsrstr;
4519
+
4520
+            } else {
4521
+
4522
+                // Save the available phone numbers for the current user
4523
+                $availablenmbrs = implode("|", $currentnmbrs);
4524
+                $savephno = $this->connection->prepare('UPDATE `*PREFIX*sms_relent_settings` SET `available_numbers` = ? WHERE `user_id` = ?');
4525
+                $upusrphnmbrs = $savephno->execute([$availablenmbrs, $userId]);
4526
+	        $upusrphnmbrs->closeCursor();
4527
+
4528
+                return $currentnmbrs; 
4529
+            }
4530
+        }
4531
+    }
4532
+}
0 4533
new file mode 100644
... ...
@@ -0,0 +1,259 @@
1
+<?php
2
+/**
3
+ * @copyright 2021 Double Bastion LLC <www.doublebastion.com>
4
+ *
5
+ * @author Double Bastion LLC
6
+ *
7
+ * @license GNU AGPL version 3 or any later version
8
+ *
9
+ * This program is free software; you can redistribute it and/or
10
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
11
+ * License as published by the Free Software Foundation; either
12
+ * version 3 of the License, or any later version.
13
+ *
14
+ * This program is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
18
+ *
19
+ * You should have received a copy of the GNU Affero General Public
20
+ * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
+ *
22
+ */
23
+
24
+declare(strict_types=1);
25
+
26
+script('sms_relentless', 'sendsms');
27
+script('sms_relentless', 'showsmstables');
28
+script('sms_relentless', 'deleteoldsms');
29
+style('sms_relentless', 'style');
30
+
31
+?>
32
+
33
+
34
+<div id="smsrelentless_vbar">
35
+
36
+       <div id="currentbaldiv" class="cllridcls">
37
+            <div id="showsum">Balance:</div>
38
+            <select id="smsprovider" class="optselectprov">
39
+                    <option value="" selected="selected" disabled hidden class="selectsmsprov">see balance</option>
40
+            </select>
41
+            <span id="currentbalance"></span>
42
+            <div class="tooltipbalanceid">
43
+                <div id="infobalance">i</div>
44
+                <span class="balancetooltip">To see the current balance, select a provider from the drop-down list. The balance will be rounded to 3 decimal places and the
45
+                      currency will be that of the respective account. You can see Telnyx prices <a href="https://telnyx.com/pricing/messaging" style="color:#1b60ba"
46
+                      target="_blank" rel="noreferrer noopener">here</a>, Plivo prices <a href="https://www.plivo.com/sms/pricing/us/" style="color:#1b60ba" target="_blank"
47
+                      rel="noreferrer noopener">here</a>, Twilio prices <a href="https://www.twilio.com/sms/pricing/ro" style="color:#1b60ba" target="_blank" 
48
+                      rel="noreferrer noopener">here</a> and Flowroute prices <a href="https://flowroute.com/pricing-details/"  style="color:#1b60ba" target="_blank" 
49
+                      rel="noreferrer noopener">here</a>.
50
+                </span>
51
+            </div>
52
+       </div>
53
+
54
+       <div id="smsnumbersdiv" class="cllridcls">
55
+            <div id="pickid">Set ID:</div>
56
+            <select id="currentsmsnmbrs" class="optselectsmsnb">
57
+                  <option value='' class="optselectsmsnb" selected disabled hidden>getting numbers ...</option>
58
+            </select>
59
+            <button id="refreshSenderIDs" title="Refresh the list of Sender IDs."></button>
60
+            <div class="tooltipsetid">
61
+                <div id="infotipid">i</div>
62
+                <div id="setcalleridtp">
63
+                    <span class="calleridtooltip">If you see more than one phone number in the drop-down list, select a number or an alphanumeric ID as Sender ID. The Sender ID is 
64
+                        the 'From' field that is displayed on the phone of the receivers, when they receive your message. It can be a phone number or an alphanumeric sequence. To 
65
+                        choose an alphanumeric sequence as Sender ID, it must be first saved in 'Administration settings' > 'Administration' > 'SMS Relentless' > 'Telnyx/Plivo/Twilio 
66
+                        alphanumeric Sender ID' field. 
67
+                        <font style="color:#aa2e4b">There are local restrictions based on market regulations or carrier-specific, that can prevent SMS
68
+                        messages to reach their destination because of their Sender ID.</font> For example, in USA and Canada, incoming SMS messages with alphanumeric Sender IDs
69
+                        are not accepted. All messages to phone numbers in USA and Canada must have a phone number as Sender ID. Before sending SMS messages to a country,
70
+                        it's recommended to read about the <a href="https://support.twilio.com/hc/en-us/articles/223133767-International-support-for-Alphanumeric-Sender-ID" 
71
+                        style="color:#1b60ba" target="_blank" rel="noreferrer noopener">Sender ID restrictions</a> specific to that country. If you use alphanumeric Sender IDs, 
72
+                        there are even <a href="https://support.plivo.com/hc/en-us/articles/360048268071" style="color:#1b60ba" target="_blank" rel="noreferrer noopener">countries</a> 
73
+                        that require that you preregister your Sender ID. If you use Telnyx, to be able to select a phone number as Sender ID, you must have a 'Messaging Profile' 
74
+                        associated with that phone number.
75
+                    </span>
76
+                </div>
77
+            </div>
78
+       </div>
79
+
80
+       <div  class="srheader">
81
+            Enter the recipient's number as:
82
+       </div>
83
+       <div class="smsnbformat">
84
+            <a href="https://en.wikipedia.org/wiki/List_of_country_calling_codes#Alphabetical_order" style="color:#1b60ba"
85
+               target="_blank" rel="noreferrer noopener">CountryCallingCode</a><font style="color:#aa2e4b">PhoneNumber</font>
86
+       </div>
87
+       <div class="fortooltip"><font class="texttooltip">i</font>
88
+         <div id="tonmbrformat">
89
+            <span class="fortooltiptext">
90
+               For example, to send an SMS to the German number 1212121212, enter 491212121212, where 49 is the country calling code of Germany. The
91
+               <a href="https://en.wikipedia.org/wiki/List_of_country_calling_codes#Alphabetical_order"
92
+               style="color:#1b60ba" target="_blank" rel="noreferrer noopener">country calling code</a> must be always included, even if the SMS is sent locally. You don't need to add 
93
+               the '+' sign or '00' in front of the number. <font style="color:#aa2e4b">In different countries there are market regulations and restrictions that
94
+               can prevent certain SMS messages to reach their destination (such as when the text contains repetitive URLs) or can make them illegal (such as when sending messages that 
95
+               advertise money-lending services).</font> Before sending SMS messages to a country, it's recommended to read about the 
96
+               <a href="https://support.twilio.com/hc/en-us/articles/223133767-International-support-for-Alphanumeric-Sender-ID" style="color:#1b60ba" target="_blank" rel="noreferrer noopener">
97
+               restrictions</a> that apply to that country. To send the same message to multiple recipients, you can enter their phone numbers one after the other separated by comma, 
98
+               in the phone number field. If you want to send the same message to more than 10 phone numbers at once, it's recommended to upload a txt/csv file containing the recipients' 
99
+               phone numbers, by using the option from below. If you check that checkbox, you will be able to upload a file containing phone numbers.
100
+            </span>
101
+         </div>
102
+       </div>
103
+
104
+   <div id="smstodiv">
105
+       <input type="text" id="smsto" name="smsto" />
106
+   </div>
107
+
108
+   <div id="sendtomultiple">Upload file with phone numbers:</div><input type="checkbox" id="tomultchckbx" />
109
+
110
+   <div id="multiplerecivers">
111
+       <div class="fortooltipsec"><font class="texttooltip">i</font>
112
+          <div id="uploadfileinfo">
113
+          <span class="fortooltiptextsec">To send an SMS to a large number of recipients, upload a file containing the recipients' phone numbers.
114
+              Supported formats are txt and csv. The phone numbers can be separated by comma (,) , semicolon (;) , vertical bar (|) , or by new line (by listing one number per line).
115
+              The duplicate phone numbers will be automatically removed. If the numbers contain dots, hyphens or plus signs, they will be also automatically removed.
116
+              After uploading the file, enter the time interval in milliseconds (1 second has 1000 milliseconds) between two consecutive message sending requests,
117
+              in the text box from below. It's important to note that SMS providers impose restrictions upon the message sending rate and there are also country specific and 
118
+              carrier specific restrictions regarding the frequency of outgoing/incoming messages. For Telnyx, the allowed SMS sending rate for US or 
119
+              Canadian long code numbers (10 digit numbers) is 
120
+              <a href="https://support.telnyx.com/en/articles/96934-throughput-limit-for-outbound-long-code-sms" style="color:#1b60ba" target="_blank" rel="noreferrer noopener">1 
121
+              message per 6 seconds per number</a> . If you need a higher throughput per number, you can rent toll-free numbers (with sending rates of 20 messages per second per number)
122
+              or short codes (with sending rates of 1000 messages per second per number). For Plivo, if you have rented a US or Canadian 10 digit number, you can send SMS messages at 
123
+              a rate of <a href="https://support.plivo.com/hc/en-us/articles/360041314852-What-s-the-outgoing-rate-limit-for-SMS-messages-" style="color:#1b60ba" target="_blank" 
124
+              rel="noreferrer noopener">1 message per 4 seconds per number</a>. If you need a higher throughput, you can rent toll-free numbers (with rates of 10 messages per second per 
125
+              number) or short codes (with rates of 100 messages per second per number). For Twilio, a US or Canadian 10 digit number can send 
126
+              <a href="https://support.twilio.com/hc/en-us/articles/115002943027-Understanding-Twilio-Rate-Limits-and-Message-Queues" style="color:#1b60ba" target="_blank"
127
+              rel="noreferrer noopener">1 message per second</a>. If you need a higher throughput, you can send 3 messages per second per number with toll-free numbers, or 100 messages 
128
+              per second per number with short codes. For Flowroute, using a US or Canadian 10 digit number or toll-free number, you can send 
129
+              <a href="https://developer.flowroute.com/docs/flowroute-messaging-rate-limits/" style="color:#1b60ba" target="_blank" rel="noreferrer noopener">4 messages per second
130
+              per account</a> (accross all phone numbers). These sending rate limits don't necessarily apply when using non-US and non-Canadian phone numbers to send SMS messages to 
131
+              non-US and non-Canadian numbers. Also, in general, custom sending rates may be obtained by contacting Telnyx/Plivo/Twilio/Flowroute support. Starting from 2021, if you 
132
+              want to send A2P (<a href="https://www.plivo.com/docs/sms/concepts/terminology" style="color:#1b60ba" target="_blank" rel="noreferrer noopener">Application-To-Person</a>) 
133
+              SMS messages to phone numbers or from phone numbers belonging to certain carriers in the US, such as AT&T and T-Mobile, you will need to register your brand and your 
134
+              campaign via
135
+              <a href="https://support.telnyx.com/en/articles/3679260-frequently-asked-questions-about-10dlc" style="color:#1b60ba" target="_blank" rel="noreferrer noopener">Telnyx</a>/
136
+              <a href="https://support.plivo.com/hc/en-us/articles/4682352262809-How-to-Register-10DLC-Brands-and-Campaigns" style="color:#1b60ba" target="_blank" rel="noreferrer noopener">Plivo</a>/
137
+              <a href="https://support.twilio.com/hc/en-us/articles/1260801864489-How-do-I-register-to-use-A2P-10DLC-messaging-" style="color:#1b60ba" target="_blank" rel="noreferrer noopener">Twilio</a>/ 
138
+              <a href="https://support.flowroute.com/265034-Messaging-Guidelines---10DLC-Carrier-Fees-and-Registration" style="color:#1b60ba" target="_blank" rel="noreferrer noopener">Flowroute</a>. 
139
+              Registered campaigns also benefit from a much higher message sending rate, which differs from one use case to another. If you leave the text box from below empty, the 
140
+              application will try to send all the messages with the default sending rate of 1 message per second. If you send messages from a US or Canadian long code number and you 
141
+              surpass the limit of 1 message per 6 seconds for Telnyx or 1 message per 4 seconds for Plivo, or 1 message per 1 second for Twilio, or 4 messages per second for Flowroute,
142
+              Telnyx/Plivo/Twilio/Flowroute respectively will queue your messages and will send them at the specified rates in the order they were received. However, if you send a large 
143
+              number of messages, when the queue becomes full, new messages can be rejected and lost, therefore, to prevent message loss, it's recommended to set the right sending rate 
144
+              in the text box from below.
145
+          </span>
146
+          </div>
147
+       </div>
148
+       <div id="multsetrows">
149
+          <div id="fileuploadednm" class="fileuploadstl"></div>
150
+          <div class="uploadfiledv">
151
+              <form class="uploadflbt"  enctype="multipart/form-data" >
152
+                  <label for="uploadfileforsms" class="pfprompt"><span id="uploadflprmpt"><?php p($l->t('Upload the file ')) ?></span></label>
153
+                  <input id="uploadfileforsms" class="fileupload" name="uploadedtosms" type="file" />
154
+                  <label for="uploadfileforsms" class="button icon-upload svg" id="uploadfileforsms" </label>
155
+              </form>
156
+          </div>
157
+          <span id="sms_upload_msg"></span>
158
+          <span class="entertime">Enter the time interval between consecutive messages, in milliseconds:</span><input type="text"
159
+          id="multsmsinterval" placeholder="Eg.: 1000" />
160
+       </div>
161
+   </div>
162
+
163
+   <div id="entermessage">Enter message:</div>
164
+   <textarea id="smstext"  name="smstext" placeholder="Enter a message here, then press 'Send SMS'."></textarea>
165
+
166
+   <div class="maxmessagelength"><font class="texttooltip">i</font>
167
+       <div id="maxlengthinfo">
168
+           <span class="maxlengthtooltip">
169
+                The maximum length allowed for SMS messages using the standard GSM 03.38 encoding is 160 characters (fewer in some countries),
170
+                while for Unicode encoded messages is 70 characters. If you send an SMS message longer than 160 characters for standard GSM encoding or longer than 70 
171
+                characters for Unicode encoding, the message will be sent as a 'concatenated' message: it will be split into smaller pieces by Telnyx/Plivo/Twilio/Flowroute 
172
+                and it will be reassembled as one message at its destination. However, you will be charged for each piece as for a separate SMS. Thus, if the initial message 
173
+                is 385 GSM encoded characters in length, you will be charged for 3 SMS messages. The maximum number of characters per concatenated message is slightly smaller 
174
+                than the standard 160 for GSM encoded characters and 70 for Unicode, due to the inclusion of concatenation headers. Some symbols in the GSM 7-bit alphabet 
175
+                table (like "£" or "€") will count as two characters, therefore, not always 160 characters will fit into a single GSM encoded SMS message. The maximum length 
176
+                for MMS messages is different. MMS messages can be up to 1600 characters long.
177
+           </span>
178
+       </div>
179
+   </div>
180
+
181
+   <div id="char_count"><span id="countchnb"></span><span> characters</span></div>
182
+   <div id="mtextSize"><span id="textsizeinkb"></span><span> KB</span></div>
183
+
184
+   <div id="sendmediafl">
185
+        <span>Select file(s) to send as MMS:</span><input type="checkbox" id="mediafilechckbx" />
186
+   </div>
187
+
188
+   <div id="upmediafiles">
189
+
190
+       <div class="fortooltipfourth"><div id="infotipmms">i</div>
191
+          <div id="uploadmmfileinfo">
192
+             <span id="tooltiptextfourth">To send an MMS message, you can upload media files or pick them from Nextcloud.</span>
193
+          </div>
194
+       </div>
195
+
196
+       <div class="srheaderch">Choose the file(s) that you want to send as MMS:</div>
197
+
198
+          <div id="filestotsize">Total files size:<span id="filessizetext"></span> KB</div>
199
+
200
+          <div id="mmsfileuploadednm" class="fileuploadstl"></div>
201
+          <div class="uploadfiledv">
202
+               <form class="uploadflbt"  enctype="multipart/form-data" >
203
+                     <span id="uploadFile">Upload file</span>
204
+                     <input id="uploadfileformms" class="fileupload" name="uploadedtomms[]" type="file" multiple />
205
+                     <label for="uploadfileformms" class="button icon-upload svg" id="uploadfileformms" </label>
206
+               </form>
207
+          </div>
208
+
209
+       <span id="pf_upload_msg"></span>
210
+
211
+       <div id="filespickednc" class="filesfromnc"></div>
212
+  
213
+       <div id="pickfilesNext"><span id="pickFromNext">Pick from Nextcloud</span><button id="choosefilen"></button></div>
214
+
215
+       <span id="pf_choose_msg"></span>
216
+
217
+       <p class="pickedflnm"></p>
218
+
219
+   </div>
220
+
221
+   <input type="submit" id="submitsms" value="Send SMS" />
222
+   <span id="sms_submit_msg"></span>
223
+
224
+   <div id="dirbuttons">
225
+       <button id="receivedsmstableshow" class="opensmsfolder">Received Messages</button>
226
+       <button id="sentsmstableshow" class="opensmsfolder">Sent Messages</button>
227
+       <button id="groupedtableshow" class="opensmsfolder">Messages Grouped by Number</button>
228
+   </div>
229
+
230
+
231
+   <div id="deleteoldmssgs">Remove old messages:</div><input type="checkbox" id="deleteoldchckbox" />
232
+
233
+   <div id="deleteoldsms">
234
+       <div class="fortooltiptert"><font class="texttooltip">i</font>
235
+          <div id="deleteoldinfo">
236
+             <span class="fortooltiptexttert">Since this application records all incoming and outgoing SMS messages, in time, its database can become very large, which
237
+                 can slow it down. To avoid having to work with extremely large tables, it's recommended that you delete from time to time all the sent/received messages older than 
238
+                 a specified number of days (for example 180 days). All the messages deleted using the options from below will be preserved, because they will be saved as csv files
239
+                 before being deleted from the database. The csv files will contain all the data of the deleted messages, they will bear the date of the removal and they will be
240
+                 stored in the 'SMS_Relentless/ removed_sent_messages' and 'SMS_Relentless/ removed_received_messages' directories. Being structured as 'csv',
241
+                 the data can then be viewed and analyzed with other applications to create statistics, graphs etc. Therefore, as long as the 'csv' files are preserved,
242
+                 the deleted messages are not lost. (Please note that this 'save before delete' mechanism is not used when messages are deleted by selecting their respective table 
243
+                 rows and clicking on the 'Permanently delete' upper-left corner icon).
244
+          </span>
245
+          </div>
246
+       </div>
247
+       <div id="delsetrows">
248
+          <span class="deletesmsolder">Delete from the database all the <font style="color: #ba3555;">received</font> messages that are older than <input type="text" id="oldrecSmsInterval" title="Enter the number of days." /> days.</span>
249
+          <input type="submit" id="delOldrecSMS" value="Delete received messages" />
250
+          <span id="sms_deleterecmsg"></span><br><br>
251
+
252
+          <span class="deletesmsolder">Delete from the database all the <font style="color: #ba3555;">sent</font> messages that are older than </span><input type="text" id="oldsentSmsInterval" title="Enter the number of days."/>
253
+          <span class="deletesmsolder"> days.</span>
254
+          <input type="submit" id="delOldsentSMS" value="Delete sent messages" />
255
+          <span id="sms_deletesentmsg"></span>
256
+       </div>
257
+   </div>
258
+
259
+</div>
0 260
new file mode 100644
... ...
@@ -0,0 +1,299 @@
1
+<?php
2
+/**
3
+ * @copyright 2021 Double Bastion LLC <www.doublebastion.com>
4
+ *
5
+ * @author Double Bastion LLC
6
+ *
7
+ * @license GNU AGPL version 3 or any later version
8
+ *
9
+ * This program is free software; you can redistribute it and/or
10
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
11
+ * License as published by the Free Software Foundation; either
12
+ * version 3 of the License, or any later version.
13
+ *
14
+ * This program is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
18
+ *
19
+ * You should have received a copy of the GNU Affero General Public
20
+ * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
+ *
22
+ */
23
+
24
+declare(strict_types=1);
25
+
26
+script('sms_relentless', 'adminsettings');
27
+style('sms_relentless', 'style');
28
+
29
+?>
30
+
31
+<div id="sms_relentless_adm">
32
+
33
+        <div class="section">
34
+           <h2><?php p($l->t('SMS Relentless'));?></h2>
35
+           <p id="settings-dscr"><h3><?php p($l->t('Enter your credentials and options in the fields from below. As SMS service provider you can use Telnyx, Plivo, Twilio or 
36
+               Flowroute, or all of them:')); ?></h3></p><br>
37
+           <div class="sms_followupsection">
38
+
39
+                <form id="admin_conf" action="#" >
40
+
41
+                   <div class="providerSettings">
42
+                   <p class="providerName">Telnyx Settings</p>
43
+                   <p><label for="telapi_key" class="setlabeltext"><b>Telnyx API Secret Key</b> (Log in to Telnyx, then, on the 'Home' page, in the 'API Keys' section from the upper 
44
+                          right corner, click on 'Manage Keys'. If you already have an API key, just copy it by clicking the 'Copy to clipboard' icon. Otherwise, to create an API key, 
45
+                          click the 'Create API Key' button, on the pop up message click 'Create', then enter it in the field from below.):</label></p>
46
+                   <input type="password" class="smsr_textbox" id="telapi_key" name="telapi_key" autocomplete="false"
47
+                          placeholder="e.g. d6f172ce92e4f2 ..." /><br>
48
+
49
+                   <p><label for="tel_pub_key" class="setlabeltext"><b>Telnyx Account Public Key</b> (While logged in to Telnyx, on the 'Home' page, in the 'API Keys' section from the 
50
+                          upper right corner, click on 'Manage Keys', then click on 'Public Key' on the upper bar, then copy the key from the 'Key' field and enter it in the field from 
51
+                          below.):</label></p>
52
+                   <input type="password" class="smsr_textbox" id="tel_pub_key" name="tel_pub_key" autocomplete="false"
53
+                          placeholder="e.g. KLCnMsTSp8utW3RRHx0FiXxbf5BxK2Y5q8mMTCn0jgv=" /><br>
54
+
55
+                   <p><label for="messaging_profile_id" class="setlabeltext"><b>Messaging Profile ID</b> (While logged in to Telnyx, click on 'Messaging', then on 'Programmable 
56
+                       Messaging' on the left panel, click on the name of the messaging profile that you want to use, then under 'Profile ID' you will find the messaging profile ID. 
57
+                       Copy it and enter it in the field from below.):
58
+                   </label></p>
59
+                   <input type="password" class="smsr_textbox" id="messaging_profile_id" name="messaging_profile_id" autocomplete="false"
60
+                          placeholder="e.g. 9d4f47b6-26c9-d25c-c2f5 ..." /><br>
61
+
62
+                   <p><label for="telapi_url_rec" class="setlabeltext"><b>Telnyx webhook URL for incoming SMS/MMS</b> (You have to first generate and then copy this URL into your Telnyx
63
+                       account, so that Telnyx knows where to deliver the SMS/MMS messages received by your Telnyx phone number(s). First generate the URL by pressing the button from
64
+                       below, copy it, then, in your Telnyx account click on 'Messaging' then on 'Programmable Messaging' on the left panel, click on the name of the messaging profile 
65
+                       that you associated with your phone number(s), then, under 'Inbound Settings', enter the webhook URL generated here in the field 'Send a webhook to this URL' and 
66
+                       click the 'Save' button. Don't forget to also click the 'Save' button at the bottom of this page after entering all the credentials, to save all the settings to 
67
+                       the database.)</label></p>
68
+                   <input type="button" id="generate_tel_rcpt" class="generateUrl" value="<?php p($l->t('Generate new webhook URL for incoming SMS/MMS')) ?>" />
69
+                   <input type="text" class="smsr_textboxspec" id="telapi_url_rec" name="telapi_url_rec" autocomplete="false" />
70
+                   <span id="copyToClipboardtel" class="icon icon-clippy" title="Copy to clipboard"></span><br><br>
71
+
72
+                   <p><label for="telapi_url" class="setlabeltext"><b>Telnyx webhook URL for delivery receipts</b> (This URL will be included by SMS Relentless in message sending 
73
+                       requests, so that Telnyx will know where to send the delivery receipts. Just generate it by pressing the button from below.
74
+                       You don't have to enter this URL into your Telnyx account. Don't forget to click the 'Save' button at the bottom of this page after entering all the credentials, 
75
+                       to save all the settings to the database.)</label></p>
76
+                   <input type="button" id="generate_tel_delrcpt" class="generateUrl" value="<?php p($l->t('Generate new webhook URL for delivery receipts')) ?>" />
77
+                   <input type="text" id="telapi_url" name="telapi_url" autocomplete="false" /><br><br>
78
+
79
+                   <p><label for="tel_sender_name" class="setlabeltext"><b>Telnyx alphanumeric Sender ID</b> (If you intend to use an alphanumeric Sender ID, enter an alphanumeric 
80
+                          sequence of up to 11 characters in the range of a-z, A-Z, 0-9 and space. In certain countries there are regulations that accept only shorter alphanumeric 
81
+                          Sender IDs, such as up to 6 characters. You cannot send SMS/MMS messages with alphanumeric Sender IDs to USA or Canada. There are even 
82
+                          <a href="https://support.plivo.com/hc/en-us/articles/360041448032" style="color:#1b60ba" target="_blank" rel="noreferrer noopener">countries</a> that require
83
+                          preregistration of alphanumeric Sender IDs. Before sending SMS/MMS messages to a country, it's recommended to read the
84
+                          <a href="https://support.twilio.com/hc/en-us/articles/223133767-International-support-for-Alphanumeric-Sender-ID" style="color:#1b60ba" target="_blank"
85
+                          rel="noreferrer noopener">country specific features and restrictions.</a> Some carriers won't accept messages with an alphanumeric Sender ID): </label></p>
86
+                   <input type="text" class="smsr_textbox" id="tel_sender_name" name="tel_sender_name" autocomplete="false"
87
+                          placeholder="e.g. Smart Inc" /><br><br>
88
+
89
+                   <p><label for="tnxKeysAccessTbl" class="setlabeltext"><b>Allow the following groups and non-admin users to send and receive messages using the Telnyx API Secret Key, 
90
+                          Public Key, messaging profile ID and alphanumeric Sender ID mentioned above (to be able to use them properly, the users with whom these credentials are shared 
91
+                          will have to access their app Settings page, generate the two webhook URLs for Telnyx by clicking the corresponding 'Generate new webhook URL ...' buttons, and
92
+                          then click the 'Save' button at the bottom of that page):</b></label></p><br>
93
+
94
+                   <table id="tnxKeysAccessTbl">
95
+
96
+                      <tr><th>Groups Allowed</th><th style="max-width: 40px !important"></th><th>Users Allowed</th><th style="max-width: 40px !important"></th><th></th></tr>
97
+                      <tr><td><div id="alwdakeyGrps-tnx" class="alwdKeysGroups"></div></td><td><div id="showakeyGrps-tnx" class="showAllGroupsak">
98
+                      <img class="srGroupImg" style="cursor:pointer" title="Show all groups"></div></td><td><div id="alwdakeyUsrs-tnx" class="alwdKeysUsers"></div>
99
+                      </td><td><div id="showakeyUsrs-tnx" class="showAllUsersak"><img class="srUserImg" style="cursor:pointer" title="Show all users"></div></td>
100
+                      <td><input type="submit" id="alwdrstsave-tnx" class="savealwdKeys" value="Edit" title="Edit Row" /></td></tr>
101
+
102
+                   </table><br>
103
+
104
+                   </div><br><br><br>
105
+
106
+                   <div class="providerSettings">
107
+                   <p class="providerName">Plivo Settings</p>
108
+                   <p><label for="nexapi_key" class="setlabeltext"><b>Plivo Auth ID</b> (Log in to Plivo. On the first page, which is the Overview page, under Account, copy the 'Auth ID'
109
+                          and enter it in the field from below.):</label></p>
110
+                   <input type="password" class="smsr_textbox" id="nexapi_key" name="nexapi_key" autocomplete="false"
111
+                          placeholder="e.g. r5g974cb92e4t1 ...'" /><br>
112
+
113
+                   <p><label for="nexapi_secret" class="setlabeltext"><b>Plivo Auth Token</b> (While logged in to Plivo, on the Overview page, under Account, copy the 'Auth Token' and
114
+                          enter it in the field from below.):</label></p>
115
+                   <input type="password" class="smsr_textbox" id="nexapi_secret" name="nexapi_secret" autocomplete="false"
116
+                          placeholder="e.g. k6f489d8awn4p9 ..." /><br>
117
+
118
+                   <p><label for="nexapi_url_rec" class="setlabeltext"><b>Plivo webhook URL for incoming SMS/MMS</b> (You have to first generate and then copy this URL into your Plivo
119
+                       account, so that Plivo knows where to deliver the SMS/MMS messages received by your Plivo phone number(s). First generate the URL by pressing the button from
120
+                       below, copy it, then, in your Plivo account click on 'Messaging' on the left vertical bar, click on 'Applications', then, under 'Application name' click on
121
+                       'Inbound SMS Messages', next, under 'Message', enter the webhook URL generated here in the field 'Message URL' and select 'POST' next to it, then click the
122
+                       'Update Application' button. Don't forget to also click the 'Save' button at the bottom of this page after entering all the credentials, to save all the settings 
123
+                       to the database.)</label></p>
124
+                   <input type="button" id="generate_nex_rcpt" class="generateUrl" value="<?php p($l->t('Generate new webhook URL for incoming SMS/MMS')) ?>" />
125
+                   <input type="text" class="smsr_textboxspec" id="nexapi_url_rec" name="nexapi_url_rec" autocomplete="false" />
126
+                   <span id="copyToClipboardnex" class="icon icon-clippy" title="Copy to clipboard"></span><br><br>
127
+
128
+                   <p><label for="nexapi_url" class="setlabeltext"><b>Plivo webhook URL for delivery receipts</b> (This URL will be included by SMS Relentless in message sending 
129
+                       requests, so that Plivo will know where to send the delivery receipts. Just generate it by pressing the button from below.
130
+                       You don't have to enter this URL into your Plivo account. Don't forget to click the 'Save' button at the bottom of this page after entering all the credentials, 
131
+                       to save all the settings to the database.)</label></p>
132
+                   <input type="button" id="generate_nex_delrcpt" class="generateUrl" value="<?php p($l->t('Generate new webhook URL for delivery receipts')) ?>" />
133
+                   <input type="text" id="nexapi_url" name="nexapi_url" autocomplete="false" /><br><br>
134
+
135
+                   <p><label for="nex_sender_name" class="setlabeltext"><b>Plivo alphanumeric Sender ID:</b> (If you intend to use an alphanumeric Sender ID, enter an alphanumeric 
136
+                          sequence of up to 11 characters in the range of a-z, A-Z, 0-9 and space. In certain countries there are regulations that accept only shorter alphanumeric 
137
+                          Sender IDs, such as up to 6 characters. You cannot send SMS/MMS messages with alphanumeric Sender IDs to USA or Canada. There are even 
138
+                          <a href="https://support.plivo.com/hc/en-us/articles/360041448032" style="color:#1b60ba" target="_blank" rel="noreferrer noopener">countries</a> that require
139
+                          preregistration of alphanumeric Sender IDs. Before sending SMS/MMS messages to a country, it's recommended to read the
140
+                          <a href="https://support.twilio.com/hc/en-us/articles/223133767-International-support-for-Alphanumeric-Sender-ID" style="color:#1b60ba" target="_blank"
141
+                          rel="noreferrer noopener">country specific features and restrictions.</a> Some carriers won't accept messages with an alphanumeric Sender ID): </label></p>
142
+                   <input type="text" class="smsr_textbox" id="nex_sender_name" name="nex_sender_name" autocomplete="false"
143
+                          placeholder="e.g. Global Inc" /><br><br>
144
+
145
+                   <p><label for="plvKeysAccessTbl" class="setlabeltext"><b>Allow the following groups and non-admin users to send and receive messages using the Plivo Auth ID, Auth 
146
+                          Token and alphanumeric Sender ID mentioned above (to be able to use them properly, the users with whom these credentials are shared will have to access their 
147
+                          app Settings page, generate the two webhook URLs for Plivo by clicking the corresponding 'Generate new webhook URL ...' buttons, and then click the 'Save' 
148
+                          button at the bottom of that page):</b></label></p><br>
149
+
150
+                   <table id="plvKeysAccessTbl">
151
+
152
+                      <tr><th>Groups Allowed</th><th style="max-width: 40px !important"></th><th>Users Allowed</th><th style="max-width: 40px !important"></th></th><th></tr>
153
+                      <tr><td><div id="alwdakeyGrps-plv" class="alwdKeysGroups"></div></td><td><div id="showakeyGrps-plv" class="showAllGroupsak">
154
+                      <img class="srGroupImg" style="cursor:pointer" title="Show all groups"></div></td><td><div id="alwdakeyUsrs-plv" class="alwdKeysUsers"></div>
155
+                      </td><td><div id="showakeyUsrs-plv" class="showAllUsersak"><img class="srUserImg" style="cursor:pointer" title="Show all users"></div></td>
156
+                      <td><input type="submit" id="alwdrstsave-plv" class="savealwdKeys" value="Edit" title="Edit Row" /></td></tr>
157
+
158
+                   </table><br>
159
+
160
+                   </div><br><br><br>
161
+
162
+                   <div class="providerSettings">
163
+                   <p class="providerName">Twilio Settings</p>
164
+                   <p><label for="twilapi_key" class="setlabeltext"><b>Twilio Account SID</b> (Log in to Twilio. On the first page, under Account Info, copy the 'Account SID'
165
+                          and enter it in the field from below.):</label></p>
166
+                   <input type="password" class="smsr_textbox" id="twilapi_key" name="twilapi_key" autocomplete="false"
167
+                          placeholder="e.g. r5g974cb92e4t1 ..." /><br>
168
+
169
+                   <p><label for="twilapi_secret" class="setlabeltext"><b>Twilio Auth Token</b> (While logged in to Twilio, on the first page, under Account Info, copy the 'Auth Token'
170
+                          and enter it in the field from below.):</label></p>
171
+                   <input type="password" class="smsr_textbox" id="twilapi_secret" name="twilapi_secret" autocomplete="false"
172
+                          placeholder="e.g. k6f489d8awn4p9 ..." /><br>
173
+
174
+                   <p><label for="twilapi_url_rec" class="setlabeltext"><b>Twilio webhook URL for incoming SMS/MMS</b> (You have to first generate and then copy this URL into your 
175
+                       Twilio account, so that Twilio knows where to deliver the SMS/MMS messages received by your Twilio phone number(s). First generate the URL by pressing the button 
176
+                       from below, copy it, then, in your Twilio account click on 'Phone Numbers' on the left panel > 'Manage' > 'Active numbers', click on the phone number you want to 
177
+                       use for SMS/MMS, scroll down to the 'Messaging' section, then under 'A MESSAGE COMES IN' select 'Webhook', then paste in the webhook URL that you have just 
178
+                       generated and select 'HTTP POST' as the request type. Enter the same data under 'PRIMARY HANDLER FAILS', then click the 'Save' button. If you have multiple 
179
+                       SMS/MMS enabled phone numbers, do the same for each number. Don't forget to also click the 'Save' button at the bottom of this page after entering all the 
180
+                       credentials, to save all the settings to the database.)</label></p>
181
+                   <input type="button" id="generate_twil_rcpt" class="generateUrl" value="<?php p($l->t('Generate new webhook URL for incoming SMS/MMS')) ?>" />
182
+                   <input type="text" class="smsr_textboxspec" id="twilapi_url_rec" name="twilapi_url_rec" autocomplete="false" />
183
+                   <span id="copyToClipboardtwil" class="icon icon-clippy" title="Copy to clipboard"></span><br><br>
184
+
185
+                   <p><label for="twilapi_url" class="setlabeltext"><b>Twilio webhook URL for delivery receipts</b> (This URL will be included by SMS Relentless in message sending 
186
+                       requests, so that Twilio will know where to send the delivery receipts. Just generate it by pressing the button from below.
187
+                       You don't have to enter this URL into your Twilio account. Don't forget to click the 'Save' button at the bottom of this page after entering all the credentials, 
188
+                       to save all the settings to the database.)</label></p>
189
+                   <input type="button" id="generate_twil_delrcpt" class="generateUrl" value="<?php p($l->t('Generate new webhook URL for delivery receipts')) ?>" />
190
+                   <input type="text" id="twilapi_url" name="twilapi_url" autocomplete="false" /><br><br>
191
+
192
+                   <p><label for="twil_sender_name" class="setlabeltext"><b>Twilio alphanumeric Sender ID:</b> (If you intend to use an alphanumeric Sender ID, enter an alphanumeric 
193
+                          sequence of up to 11 characters in the range of a-z, A-Z, 0-9 and space. In certain countries there are regulations that accept only shorter alphanumeric 
194
+                          Sender IDs, such as up to 6 characters. You cannot send SMS/MMS messages with alphanumeric Sender IDs to USA or Canada. There are even 
195
+                          <a href="https://support.plivo.com/hc/en-us/articles/360041448032" style="color:#1b60ba" target="_blank" rel="noreferrer noopener">countries</a> that require
196
+                          preregistration of alphanumeric Sender IDs. Before sending SMS/MMS messages to a country, it's recommended to read the
197
+                          <a href="https://support.twilio.com/hc/en-us/articles/223133767-International-support-for-Alphanumeric-Sender-ID" style="color:#1b60ba" target="_blank"
198
+                          rel="noreferrer noopener">country specific features and restrictions.</a> Some carriers won't accept messages with an alphanumeric Sender ID): </label></p>
199
+                   <input type="text" class="smsr_textbox" id="twil_sender_name" name="twil_sender_name" autocomplete="false"
200
+                          placeholder="e.g. Global Inc" /><br><br>
201
+
202
+                   <p><label for="twlKeysAccessTbl" class="setlabeltext"><b>Allow the following groups and non-admin users to send and receive messages using the Twilio Account SID, 
203
+                          Auth Token and alphanumeric Sender ID mentioned above (to be able to use them properly, the users with whom these credentials are shared will have to access 
204
+                          their app Settings page, generate the two webhook URLs for Twilio by clicking the corresponding 'Generate new webhook URL ...' buttons, and then click the 
205
+                          'Save' button at the bottom of that page):</b></label></p><br>
206
+
207
+                   <table id="twlKeysAccessTbl">
208
+
209
+                      <tr><th>Groups Allowed</th><th style="max-width: 40px !important"></th><th>Users Allowed</th><th style="max-width: 40px !important"></th></th><th></tr>
210
+                      <tr><td><div id="alwdakeyGrps-twl" class="alwdKeysGroups"></div></td><td><div id="showakeyGrps-twl" class="showAllGroupsak">
211
+                          <img class="srGroupImg" style="cursor:pointer" title="Show all groups"></div></td>
212
+                          <td><div id="alwdakeyUsrs-twl" class="alwdKeysUsers"></div></td><td><div id="showakeyUsrs-twl" class="showAllUsersak">
213
+                          <img class="srUserImg" style="cursor:pointer" title="Show all users"></div></td>
214
+                          <td><input type="submit" id="alwdrstsave-twl" class="savealwdKeys" value="Edit" title="Edit Row" /></td></tr>
215
+
216
+                   </table><br>
217
+
218
+                   </div><br><br><br>
219
+
220
+                   <div class="providerSettings">
221
+                   <p class="providerName">Flowroute Settings</p>
222
+                   <p><label for="flowapi_key" class="setlabeltext"><b>Flowroute Access Key</b> (Log in to Flowroute. On the left panel, click on 'Preferences', then on the 'API Control'
223
+                          tab. Scroll down to the 'API Keys' section. If you already have a pair of keys listed in that section, just copy the Access Key to the field from below. If you
224
+                          haven't created any keys yet, to create a key pair, under 'Add new API Key', in the 'Name' field, enter a name for the new key pair. In the 'Description' field 
225
+                          enter a short description, then click 'Add new'. A new pair of keys will be created and you will be prompted to copy the Secret Key. After you copy the Secret 
226
+                          Key to a safe location, copy the Access Key that has just been created to the field from below.):</label></p>
227
+                   <input type="password" class="smsr_textbox" id="flowapi_key" name="flowapi_key" autocomplete="false"
228
+                          placeholder="e.g. r5g974cb92e4t1 ..." /><br>
229
+
230
+                   <p><label for="flowapi_secret" class="setlabeltext"><b>Flowroute Secret Key</b> (Enter the Secret Key created earlier and copied to a safe place, in the field from 
231
+                          below.):</label></p>
232
+                   <input type="password" class="smsr_textbox" id="flowapi_secret" name="flowapi_secret" autocomplete="false"
233
+                          placeholder="e.g. k6f489d8awn4p9 ..." /><br>
234
+
235
+                   <p><label for="flowapi_url_rec" class="setlabeltext"><b>Flowroute webhook URL for incoming SMS/MMS</b> (You have to first generate and then copy this URL into your 
236
+                          Flowroute account, so that Flowroute knows where to deliver the SMS/MMS messages received by your Flowroute phone number(s). First generate the URL by pressing 
237
+                          the button from below, copy it, then, in your Flowroute account click on 'Preferences' on the left panel, then click on the 'API Control tab', turn on the 'SMS' 
238
+                          switch and in the field that shows up enter the URL that you have just generated. Click 'Save URL'. If you have an MMS enabled phone number, turn on the 'MMS' 
239
+                          switch, enter the same URL in the URL field and save it. Also, under 'SMS Webhook Version' choose 'v2.1'. Don't forget to also click the 'Save' button at the 
240
+                          bottom of this page after entering all the credentials, to save all the settings to the database.)</label></p>
241
+                   <input type="button" id="generate_flow_rcpt" class="generateUrl" value="<?php p($l->t('Generate new webhook URL for incoming SMS/MMS')) ?>" />
242
+                   <input type="text" class="smsr_textboxspec" id="flowapi_url_rec" name="flowapi_url_rec" autocomplete="false" />
243
+                   <span id="copyToClipboardflow" class="icon icon-clippy" title="Copy to clipboard"></span><br><br>
244
+
245
+                   <p><label for="flowapi_url" class="setlabeltext"><b>Flowroute webhook URL for delivery receipts</b> (This URL will be included by SMS Relentless in message sending 
246
+                          requests, so that Flowroute will know where to send the delivery receipts. Just generate it by pressing the button from below. You don't have to enter this URL 
247
+                          into your Flowroute account. Don't forget to click the 'Save' button at the bottom of this page after entering all the credentials, to save all the settings 
248
+                          to the database.)</label></p>
249
+                   <input type="button" id="generate_flow_delrcpt" class="generateUrl" value="<?php p($l->t('Generate new webhook URL for delivery receipts')) ?>" />
250
+                   <input type="text" id="flowapi_url" name="flowapi_url" autocomplete="false" /><br><br>
251
+                   <span style='color:#272727'>Flowroute only supports sending/receiving SMS/MMS messages within USA and Canada and it doesn't support Alphanumeric Sender IDs.</span><br><br>
252
+
253
+                   <p><label for="flrKeysAccessTbl" class="setlabeltext"><b>Allow the following groups and non-admin users to send and receive messages using the Flowroute Access Key 
254
+                          and Secret Key mentioned above (to be able to use them properly, the users with whom these credentials are shared will have to access their app Settings page, 
255
+                          generate the two webhook URLs for Flowroute by clicking the corresponding 'Generate new webhook URL ...' buttons, and then click the 'Save' button at the 
256
+                          bottom of that page):</b></label></p><br>
257
+
258
+                   <table id="flrKeysAccessTbl">
259
+
260
+                      <tr><th>Groups Allowed</th><th style="max-width: 40px !important"></th><th>Users Allowed</th><th style="max-width: 40px !important"></th></th><th></tr>
261
+                      <tr><td><div id="alwdakeyGrps-flr" class="alwdKeysGroups"></div></td><td><div id="showakeyGrps-flr" class="showAllGroupsak">
262
+                      <img class="srGroupImg" style="cursor:pointer" title="Show all groups"></div></td><td>
263
+                      <div id="alwdakeyUsrs-flr" class="alwdKeysUsers"></div></td><td><div id="showakeyUsrs-flr" class="showAllUsersak">
264
+                      <img class="srUserImg" style="cursor:pointer" title="Show all users"></div></td>
265
+                      <td><input type="submit" id="alwdrstsave-flr" class="savealwdKeys" value="Edit" title="Edit Row" /></td></tr>
266
+
267
+                   </table><br>
268
+
269
+                   </div><br><br><br>
270
+
271
+
272
+                   <p><label for="showallmessages" class="setlabeltext"><b>In my message tables, list not only my messages but also the messages of all the Nextcloud users 
273
+                   with whom I share the access keys mentioned above:</b></label></p>
274
+                   <input type="checkbox" class="sms_rel_checkbox" id="showallmessages" name="showallmessages" autocomplete="false" /><br>
275
+
276
+                   <p><div class="setlabeltext"><b>Restrict access to the following phone numbers:</b><div class="tooltiprestrict">
277
+                        <div id="inforestrict">i</div><div class="restricttooltext">After you allow non-admin users to use your API keys for a provider, to send and
278
+                        receive messages, they will be able to see and use all the phone numbers associated with those API keys. However, if you restrict shared phone 
279
+                        numbers to specific non-admin users, they will be able to see and use only those numbers and won't be able to see and use the other numbers 
280
+                        associated with those shared API keys.</div></div></p><br>
281
+
282
+                   <table id="phoneNmbrRestr">
283
+
284
+                      <tr><th>Restriction Author</th><th id="phoneNumberTh">Phone Number</th><th>Groups Allowed</th><th style="max-width: 40px !important"></th><th>Users Allowed</th>
285
+                      <th style="max-width: 40px !important"></th><th></th><th></th></tr>
286
+
287
+                   </table><br>
288
+
289
+                   <input type="hidden" id="user_id" name="user_id" />
290
+
291
+                   <input id="save_admin_settings" type="submit" value="<?php p($l->t('Save')) ?>" />
292
+
293
+                   <span id="smsr_save_msg"></span>
294
+
295
+               </form>
296
+           </div>
297
+        </div>
298
+</div>
299
+
0 300
new file mode 100644
... ...
@@ -0,0 +1,93 @@
1
+<?php
2
+/**
3
+ * @copyright 2021 Double Bastion LLC <www.doublebastion.com>
4
+ *
5
+ * @author Double Bastion LLC
6
+ *
7
+ * @license GNU AGPL version 3 or any later version
8
+ *
9
+ * This program is free software; you can redistribute it and/or
10
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
11
+ * License as published by the Free Software Foundation; either
12
+ * version 3 of the License, or any later version.
13
+ *
14
+ * This program is distributed in the hope that it will be useful,
15
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
18
+ *
19
+ * You should have received a copy of the GNU Affero General Public
20
+ * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
+ *
22
+ */
23
+
24
+declare(strict_types=1);
25
+
26
+script('sms_relentless', 'settings');
27
+style('sms_relentless', 'style');
28
+
29
+?>
30
+
31
+<div id="sms_relentless_adm">
32
+        <div class="section">
33
+           <h2><?php p($l->t('SMS Relentless'));?></h2>
34
+
35
+           <div id="appTitlePrg"></div>
36
+
37
+           <div class="sms_followupsection">
38
+
39
+                <form id="prov_credentials" action="#" >
40
+
41
+                   <div id="nadmProvSection"></div>
42
+
43
+                   <p><label for="messagesperpage" class="setlabeltext"><b>Number of messages per page</b> (Enter the number of messages to be displayed on one page of the
44
+                          received/sent/grouped messages tables. If you don't enter anything in this field, the default of 100 messages per page will be used.):</label></p>
45
+                   <input type="number" class="smsr_textbox" id="messagesperpage" name="messagesperpage" autocomplete="false" placeholder="e.g. 100"/><br><br>
46
+
47
+                   <p><label for="msgcheckinterval" class="setlabeltext"><b>Time interval in seconds before checking for new messages</b> (Enter the number of seconds
48
+                          before the app checks the database in the background to find if a new message has arrived, so as to know if it needs to refresh the list of received 
49
+                          messages. If you don't enter anything in this field, the default of 5 seconds will be used.):</label></p>
50
+                   <input type="number" class="smsr_textbox" id="msgcheckinterval" name="msgcheckinterval" autocomplete="false" placeholder="e.g. 5"/><br><br>
51
+
52
+                   <p><label for="showdisplaynames" class="setlabeltext"><b>Show the display name of the message author, before each message:</b></label></p>
53
+                   <input type="checkbox" class="sms_rel_checkbox" id="showdisplaynames" name="showdisplaynames" autocomplete="false" /><br>
54
+
55
+                   <p><label for="adddisplaynames" class="setlabeltext"><b>Include the display name of the message author in the text of the message itself, like this: 
56
+                        "John Doe: The weather has improved.":</b></label></p>
57
+                   <input type="checkbox" class="sms_rel_checkbox" id="adddisplaynames" name="adddisplaynames" autocomplete="false" /><br>
58
+
59
+                   <p><label for="get_notify" class="setlabeltext"><b>I want to see a notification in Nextcloud when a new SMS/MMS is received:</b></label></p>
60
+                   <input type="checkbox" class="sms_rel_checkbox" id="get_notify" name="get_notify" autocomplete="false" /><br>
61
+
62
+                   <p class="setlabeltext">To enable email notifications for every received SMS/MMS, the "sendmail" utility ("/usr/sbin/sendmail" on Debian Linux),
63
+                      has to be present on the server. "sendmail" is a binary which gets installed when Postfix is installed. Also the server user (www-data) has to be
64
+                      allowed to send emails from command line (by specifying "authorized_submit_users = www-data" in "/etc/postfix/main.cf" for Postfix on a Debian based Linux 
65
+                      distribution).</p><br>
66
+
67
+                   <p><label for="notification_email" class="setlabeltext"><b>I want to receive a notification to the email address from below, when a new SMS/MMS is
68
+                      received:</b></label></p>
69
+                   <input type="text" class="smsr_textbox" id="notification_email" name="notification_email" autocomplete="false"
70
+                          placeholder="e.g. john.doe@example.com" /><br><br>
71
+
72
+                   <p><label for="includesmsinemail" class="setlabeltext"><b>Include the SMS/MMS message in the email notification itself:</b></label></p>
73
+                   <input type="checkbox" class="sms_rel_checkbox" id="includesmsinemail" name="includesmsinemail" autocomplete="false" /><br>
74
+
75
+                   <p><label for="showdisplaynames" class="setlabeltext"><b>Set auto-reply messages for the following phone numbers:</b></label></p><br>
76
+                   <table id="autoReplyTbl">
77
+                        <tr><th>Auto-reply Author</th><th id="autoRplPhoneNb">Phone Number <div class="tooltipautoreplypn"><div id="infoautoreplypn">i</div>
78
+                        <div class="autorpltooltippn">Sending a message to a phone number with a configured auto-reply from another phone number with a configured auto-reply must 
79
+                        be avoided because it will trigger an infinite loop: the 2 numbers will send auto-replies to each other incessantly, until they will consume all the available 
80
+                        funds in the balance.</div></div></th><th>Mode</th><th>Message</th><tr>
81
+                   </table><br>
82
+
83
+                   <input type="hidden" id="user_id" name="user_id" />
84
+
85
+                   <input id="save_sms_settings" type="submit" value="<?php p($l->t('Save')) ?>" title='Save settings' />
86
+
87
+                   <span id="smsr_save_msg"></span>
88
+
89
+               </form>
90
+           </div>
91
+        </div>
92
+</div>
93
+