Compare commits
241 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
2d7a2a3ff7 | ||
|
fa93d678f0 | ||
|
29f0d20be4 | ||
|
19fa70ca0e | ||
|
b1346315c2 | ||
|
5e2be0aa27 | ||
|
316e4ced29 | ||
|
bfa87343a1 | ||
|
c02def2d49 | ||
|
383d376fdc | ||
|
962a4a6f22 | ||
|
39f58e099d | ||
|
debaccfe42 | ||
|
d6aba335bc | ||
|
873d051b15 | ||
|
5b277c84f7 | ||
|
023540854c | ||
|
1a7242b468 | ||
|
e86d1c0dee | ||
|
d0aa7512c2 | ||
|
3327af9808 | ||
|
56d81018d2 | ||
|
08ff1113a6 | ||
|
36cfb436f5 | ||
|
b9810e712c | ||
|
26c67054bb | ||
|
4dbc698687 | ||
|
eecff2c514 | ||
|
db07b366fd | ||
|
ce624c4e4c | ||
|
4af2d4371e | ||
|
09118bbafa | ||
|
2561b99165 | ||
|
b30d88b02c | ||
|
c7d018e576 | ||
|
8e6535a2fe | ||
|
aa6bfd488f | ||
|
c0948070e9 | ||
|
eb757f4a79 | ||
|
f927ba1cd0 | ||
|
635147a629 | ||
|
7033e84c14 | ||
|
f3f2c385e1 | ||
|
ac9e0e8047 | ||
|
5eb0adb008 | ||
|
90886765a7 | ||
|
d8e02a5575 | ||
|
2d43153862 | ||
|
f376c830b5 | ||
|
43f759369a | ||
|
c991bd5bd7 | ||
|
597470eb2c | ||
|
2fcd1d5e9c | ||
|
77d0e34cd2 | ||
|
585c2f244b | ||
|
b646cb2104 | ||
|
8133febe5d | ||
|
d9955dd6d9 | ||
|
1e603083f9 | ||
|
0cffae3677 | ||
|
4a190271c3 | ||
|
b877ccf781 | ||
|
43ae3efccc | ||
|
f0f41fd0b2 | ||
|
964d18c33a | ||
|
5479e66347 | ||
|
b556edf7f9 | ||
|
3468ba61b6 | ||
|
1608ce46d1 | ||
|
6a8d4f1f1f | ||
|
6ad519e567 | ||
|
7f1ce426fd | ||
|
e0f25dc02a | ||
|
e8094b7d2b | ||
|
99fb0135eb | ||
|
9a7d800a15 | ||
|
770d9c6332 | ||
|
4d60c9a376 | ||
|
9dfe68c48d | ||
|
6c17b9994f | ||
|
8ac335a68d | ||
|
e0dc353be4 | ||
|
61f6d0fb42 | ||
|
94a7175886 | ||
|
224382ce9b | ||
|
feb521ec10 | ||
|
a9f572c9f3 | ||
|
2078096ba6 | ||
|
7ee735c547 | ||
|
7fa0406cac | ||
|
916131efe9 | ||
|
b01f542c91 | ||
|
68efa663b0 | ||
|
801036da26 | ||
|
f2b7360bb4 | ||
|
b10d1305a4 | ||
|
42d5fbcc16 | ||
|
0ce325a9d9 | ||
|
518780d0eb | ||
|
7a16a72630 | ||
|
2893ecb6ff | ||
|
0a06b55472 | ||
|
f0afcbdbd2 | ||
|
a5c33ce8b8 | ||
|
40fba56c6e | ||
|
25df5771df | ||
|
ba561ed556 | ||
|
b756956821 | ||
|
88d672e103 | ||
|
82cd91e761 | ||
|
55d73cd12c | ||
|
a38454a075 | ||
|
f66b2165f1 | ||
|
8e301d9b2e | ||
|
b51fc86847 | ||
|
657cee2598 | ||
|
275d7fd4e8 | ||
|
4c2d59078d | ||
|
81a426477f | ||
|
5391cd9c3f | ||
|
09db94df12 | ||
|
06eee652c4 | ||
|
2f39e54ba0 | ||
|
57a520ef68 | ||
|
b2100fb11b | ||
|
982a4fb92e | ||
|
794b8877ae | ||
|
c302592eff | ||
|
7bf580df4e | ||
|
d0c34fe288 | ||
|
7a02d9c8fb | ||
|
f4269d8f75 | ||
|
ae8be46f96 | ||
|
a0807d5dbb | ||
|
3707082d04 | ||
|
3d0c98ec87 | ||
|
0bcee11a4b | ||
|
e836c3f6a8 | ||
|
2e2d48200e | ||
|
cd14edff98 | ||
|
429a0ed252 | ||
|
c7e6443e3c | ||
|
efbc5d8e05 | ||
|
9024398522 | ||
|
cc0a85a6e9 | ||
|
442deb47b4 | ||
|
5a58dab6c0 | ||
|
c037b40961 | ||
|
9a27f70393 | ||
|
21e5ccd5a2 | ||
|
012ba8385b | ||
|
c9f1b4099f | ||
|
52f9f72e97 | ||
|
1abf4ef027 | ||
|
1819f4f63e | ||
|
ff0c890f0b | ||
|
8b9a6eb9f6 | ||
|
7a23294e7f | ||
|
dcd1d29da7 | ||
|
98137a767c | ||
|
2074f52740 | ||
|
1fdb2c61f9 | ||
|
a92d3ece6b | ||
|
71c1ffb899 | ||
|
50a7b092ff | ||
|
542108def2 | ||
|
fab6654aca | ||
|
99ca13202b | ||
|
7e3cfe6180 | ||
|
e8bf7b241d | ||
|
eeb99fe4c0 | ||
|
c930cd4e91 | ||
|
117817a0ff | ||
|
177f70cba6 | ||
|
b7a90faf76 | ||
|
0722e70a47 | ||
|
f8c0cb985c | ||
|
a4840c3c69 | ||
|
97e56818c5 | ||
|
c97f172014 | ||
|
5ce8351bbe | ||
|
2754047a32 | ||
|
eb4f6b3f6e | ||
|
d325c13610 | ||
|
3f1e03fc31 | ||
|
7de5341887 | ||
|
b7603e7b29 | ||
|
2d78d74d73 | ||
|
017da88af4 | ||
|
b0b805fd16 | ||
|
31918d786c | ||
|
ca7423ad0a | ||
|
9d4c1dcc26 | ||
|
0be27d6563 | ||
|
15b68e2225 | ||
|
2f9be22ffb | ||
|
d3fa52936c | ||
|
d56df75be2 | ||
|
f833a2c3ce | ||
|
5e0fcf9214 | ||
|
53fa65a933 | ||
|
8f12a121e4 | ||
|
0c4836128b | ||
|
99c2830d16 | ||
|
07b1a16b4e | ||
|
bc7bb42b7b | ||
|
a84835ca5b | ||
|
5994be5fe1 | ||
|
04b7e7a96c | ||
|
f6659b9e36 | ||
|
f95dea0a46 | ||
|
feea6fb6ac | ||
|
edc7253736 | ||
|
4efc689d6e | ||
|
4d559d56e9 | ||
|
7ad26ad4d8 | ||
|
d4c15b66a5 | ||
|
de4859eab9 | ||
|
adb9db12f4 | ||
|
3b35b5e9bf | ||
|
7a77aa64e1 | ||
|
be8824b889 | ||
|
7abea7cc9b | ||
|
fdcb6b4f14 | ||
|
f8e3b4bfe1 | ||
|
967a60b4c3 | ||
|
e6a2214bc9 | ||
|
c9d929e0a7 | ||
|
3b3105bc4f | ||
|
df05002bc7 | ||
|
e55ce1660d | ||
|
7ff55a4721 | ||
|
b7d929f425 | ||
|
1e7efa8e9e | ||
|
fb838e69b3 | ||
|
332baa9283 | ||
|
fac161ed78 | ||
|
fc594a52c4 | ||
|
8c289e09de | ||
|
722eddb847 | ||
|
dc06bd8f88 |
@ -12,9 +12,13 @@ SRC_DIR=`dirname $0`"/.."
|
||||
RELEASE_VERSION=${1}
|
||||
echo "Release version set to ${RELEASE_VERSION}"
|
||||
|
||||
#which npm > /dev/null
|
||||
#which gulp > /dev/null
|
||||
#which wget > /dev/null
|
||||
|
||||
sed -ri 's/(.*)<version>(.+)<\/version>/\1<version>'${RELEASE_VERSION}'<\/version>/g' ${SRC_DIR}/appinfo/info.xml
|
||||
npm install
|
||||
gulp uglify
|
||||
node_modules/gulp/bin/gulp.js uglify
|
||||
git commit -am "Release "${RELEASE_VERSION}
|
||||
git tag ${RELEASE_VERSION}
|
||||
git push
|
||||
@ -35,7 +39,8 @@ rm -Rf \
|
||||
ocsms/gulpfile.js \
|
||||
ocsms/package.json \
|
||||
ocsms/.ci \
|
||||
ocsms/.tx
|
||||
ocsms/.tx \
|
||||
ocsms/doc
|
||||
|
||||
tar cfz ocsms-${RELEASE_VERSION}.tar.gz ocsms
|
||||
echo "Release version "${RELEASE_VERSION}" is now ready."
|
||||
|
70
.github/workflows/codeql-analysis.yml
vendored
Normal file
@ -0,0 +1,70 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: '20 1 * * 4'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'javascript' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
||||
# Learn more about CodeQL language support at https://git.io/codeql-language-support
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
11
.l10nignore
Normal file
@ -0,0 +1,11 @@
|
||||
doc/swagger-ui-bundle.js
|
||||
doc/swagger-ui-bundle.js.map
|
||||
doc/swagger-ui.css
|
||||
doc/swagger-ui.css.map
|
||||
doc/swagger-ui.js
|
||||
doc/swagger-ui.js.map
|
||||
doc/swagger-ui-standalone-preset.js
|
||||
doc/swagger-ui-standalone-preset.js.map
|
||||
doc/swagger.yml
|
||||
doc/index.html
|
||||
doc/oauth2-redirect.html
|
@ -1,9 +1,10 @@
|
||||
[main]
|
||||
host = https://www.transifex.com
|
||||
lang_map = bg_BG: bg, cs_CZ: cs, fi_FI: fi, hu_HU: hu, nb_NO: nb, sk_SK: sk, th_TH: th, ja_JP: ja
|
||||
host = https://www.transifex.com
|
||||
lang_map = sk_SK: sk, th_TH: th, ja_JP: ja, bg_BG: bg, cs_CZ: cs, fi_FI: fi, hu_HU: hu, nb_NO: nb
|
||||
|
||||
[nextcloud.ocsms]
|
||||
[o:nextcloud:p:nextcloud:r:ocsms]
|
||||
file_filter = translationfiles/<lang>/ocsms.po
|
||||
source_file = translationfiles/templates/ocsms.pot
|
||||
source_lang = en
|
||||
type = PO
|
||||
type = PO
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
FROM nextcloud:14.0.3-apache
|
||||
FROM nextcloud:15.0.0-rc-apache
|
||||
|
||||
COPY . /usr/src/nextcloud/apps/ocsms
|
||||
|
15
README.md
@ -1,15 +1,14 @@
|
||||
# Phone Sync (for Nextcloud & ownCloud)
|
||||
|
||||
Phone Sync provides a webinterface to display your SMS conversations. SMS conversations are pushed by your Android devices using the [Android client](https://github.com/nerzhul/ownCloud-SMS-App), available on [Google Play Store](https://play.google.com/store/apps/details?id=fr.unix_experience.owncloud_sms).
|
||||
Phone Sync provides a webinterface to display your SMS conversations. SMS conversations are pushed by your Android devices using the [Android client](https://github.com/nerzhul/ownCloud-SMS-App), available on [F-Droid](https://f-droid.org/repository/browse/?fdid=fr.unix_experience.owncloud_sms).
|
||||
|
||||
## :arrow_forward: Access
|
||||
|
||||
The app is available in both, [Nextcloud appstore](https://apps.nextcloud.com/apps/ocsms) and [ownCloud appstore](https://apps.owncloud.com/content/show.php/ownCloud+SMS?content=167289). So installing is as easy as
|
||||
The app is available on the [Nextcloud App Store](https://apps.nextcloud.com/apps/ocsms), so installing is as easy as:
|
||||
|
||||
1. Navigate in your Nextcloud / ownCloud instance to the "apps"
|
||||
2. Enable "experimental apps" in the settings
|
||||
3. Select the category "Multimedia"
|
||||
4. Click "activate"
|
||||
1. Navigate in your Nextcloud instance to the "Apps"
|
||||
2. Select the category "Multimedia"
|
||||
3. Click "activate"
|
||||
|
||||
## :question: Solve encoding errors on MySQL
|
||||
If you are on MySQL or MariaDB and have the following issue with the database:
|
||||
@ -59,3 +58,7 @@ If you've enabled 2FA (Two Factor Authentication) logins you may be hit with an
|
||||
|
||||
## :notebook: License
|
||||
Phone Sync web application is currently licensed under [AGPL license](https://github.com/nextcloud/ocsms/blob/master/LICENSE.md).
|
||||
|
||||
## :notebook: External Libraries
|
||||
[Twemoji](https://github.com/twitter/twemoji) Code licensed under the [MIT License](http://opensource.org/licenses/MIT), Graphics licensed under [CC-BY 4.0](https://creativecommons.org/licenses/by/4.0/).
|
||||
[libphonenumber-for-php](https://github.com/giggsey/libphonenumber-for-php) Code licensed under the [Apache 2.0 License](http://www.apache.org/licenses/LICENSE-2.0).
|
||||
|
@ -1,37 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Nextcloud - Phone Sync
|
||||
*
|
||||
* This file is licensed under the Affero General Public License version 3 or
|
||||
* later. See the COPYING file.
|
||||
*
|
||||
* @author Loic Blot <loic.blot@unix-experience.fr>
|
||||
* @copyright Loic Blot 2014-2017
|
||||
*/
|
||||
|
||||
namespace OCA\OcSms\AppInfo;
|
||||
|
||||
if (class_exists('\OCP\AppFramework\App')) {
|
||||
\OC::$server->getNavigationManager()->add(array(
|
||||
// the string under which your app will be referenced in owncloud
|
||||
'id' => 'ocsms',
|
||||
|
||||
// sorting weight for the navigation. The higher the number, the higher
|
||||
// will it be listed in the navigation
|
||||
'order' => 10,
|
||||
|
||||
// the route that will be shown on startup
|
||||
'href' => \OC::$server->getURLGenerator()->linkToRoute('ocsms.sms.index'),
|
||||
|
||||
// the icon that will be shown in the navigation
|
||||
// this file needs to exist in img/
|
||||
'icon' => \OC::$server->getURLGenerator()->imagePath('ocsms', 'app.svg'),
|
||||
|
||||
// the title of your application. This will be used in the
|
||||
// navigation or on the settings page of your app
|
||||
'name' => \OCP\Util::getL10N('ocsms')->t('Phone Sync')
|
||||
));
|
||||
} else {
|
||||
$msg = 'Can not enable the OcSms app because the App Framework App is disabled';
|
||||
\OC::$server->getLogger()->error($msg, array('ocsms'));
|
||||
}
|
@ -1,268 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<database>
|
||||
<name>*dbname*</name>
|
||||
<create>true</create>
|
||||
<overwrite>false</overwrite>
|
||||
<charset>utf8</charset>
|
||||
|
||||
<table>
|
||||
<name>*dbprefix*ocsms_user_datas</name>
|
||||
<declaration>
|
||||
<field>
|
||||
<name>user_id</name>
|
||||
<type>text</type>
|
||||
<notnull>true</notnull>
|
||||
<length>64</length>
|
||||
</field>
|
||||
<field>
|
||||
<name>datakey</name>
|
||||
<type>text</type>
|
||||
<notnull>true</notnull>
|
||||
<length>64</length>
|
||||
</field>
|
||||
<field>
|
||||
<name>datavalue</name>
|
||||
<type>text</type>
|
||||
<length>64</length>
|
||||
<notnull>true</notnull>
|
||||
</field>
|
||||
<index>
|
||||
<name>user_datas_user_datakey</name>
|
||||
<field>
|
||||
<name>user_id</name>
|
||||
</field>
|
||||
<field>
|
||||
<name>datakey</name>
|
||||
</field>
|
||||
</index>
|
||||
</declaration>
|
||||
</table>
|
||||
<table>
|
||||
<name>*dbprefix*ocsms_smsdatas</name>
|
||||
<declaration>
|
||||
<field>
|
||||
<name>id</name>
|
||||
<type>integer</type>
|
||||
<default>0</default>
|
||||
<notnull>true</notnull>
|
||||
<autoincrement>1</autoincrement>
|
||||
<length>10</length>
|
||||
<primary>true</primary>
|
||||
</field>
|
||||
<field>
|
||||
<name>user_id</name>
|
||||
<type>text</type>
|
||||
<notnull>true</notnull>
|
||||
<length>64</length>
|
||||
</field>
|
||||
<field>
|
||||
<name>added</name>
|
||||
<type>timestamp</type>
|
||||
<notnull>true</notnull>
|
||||
<default>1970-01-01 00:00:00</default>
|
||||
</field>
|
||||
<field>
|
||||
<name>lastmodified</name>
|
||||
<type>timestamp</type>
|
||||
<notnull>true</notnull>
|
||||
<default>1970-01-01 00:00:00</default>
|
||||
</field>
|
||||
<field>
|
||||
<name>sms_id</name>
|
||||
<type>integer</type>
|
||||
<notnull>true</notnull>
|
||||
<length>5</length>
|
||||
</field>
|
||||
<field>
|
||||
<name>sms_address</name>
|
||||
<type>text</type>
|
||||
<notnull>true</notnull>
|
||||
<length>512</length>
|
||||
</field>
|
||||
<field>
|
||||
<name>sms_msg</name>
|
||||
<type>text</type>
|
||||
<notnull>true</notnull>
|
||||
<length>10240</length>
|
||||
</field>
|
||||
<field>
|
||||
<name>sms_date</name>
|
||||
<type>integer</type>
|
||||
<notnull>true</notnull>
|
||||
<length>10</length>
|
||||
</field>
|
||||
<field>
|
||||
<name>sms_flags</name>
|
||||
<type>text</type>
|
||||
<notnull>true</notnull>
|
||||
<default>00</default>
|
||||
<length>2</length>
|
||||
</field>
|
||||
<field>
|
||||
<name>sms_mailbox</name>
|
||||
<type>integer</type>
|
||||
<notnull>true</notnull>
|
||||
<length>1</length>
|
||||
</field>
|
||||
<field>
|
||||
<name>sms_type</name>
|
||||
<type>integer</type>
|
||||
<notnull>true</notnull>
|
||||
<length>1</length>
|
||||
</field>
|
||||
<index>
|
||||
<name>smsdata_user_mailbox</name>
|
||||
<field>
|
||||
<name>user_id</name>
|
||||
</field>
|
||||
<field>
|
||||
<name>sms_mailbox</name>
|
||||
</field>
|
||||
</index>
|
||||
<index>
|
||||
<name>smsdata_user_smsid</name>
|
||||
<field>
|
||||
<name>user_id</name>
|
||||
</field>
|
||||
<field>
|
||||
<name>sms_id</name>
|
||||
</field>
|
||||
</index>
|
||||
<index>
|
||||
<name>smsdata_user_mailbox_date</name>
|
||||
<field>
|
||||
<name>user_id</name>
|
||||
</field>
|
||||
<field>
|
||||
<name>sms_mailbox</name>
|
||||
</field>
|
||||
<field>
|
||||
<name>sms_date</name>
|
||||
</field>
|
||||
</index>
|
||||
<index>
|
||||
<name>smsdata_user_mailbox_address</name>
|
||||
<field>
|
||||
<name>user_id</name>
|
||||
</field>
|
||||
<field>
|
||||
<name>sms_mailbox</name>
|
||||
</field>
|
||||
<field>
|
||||
<name>sms_address</name>
|
||||
</field>
|
||||
</index>
|
||||
<index>
|
||||
<name>smsdata_user_mailbox_address_date</name>
|
||||
<field>
|
||||
<name>user_id</name>
|
||||
</field>
|
||||
<field>
|
||||
<name>sms_mailbox</name>
|
||||
</field>
|
||||
<field>
|
||||
<name>sms_address</name>
|
||||
</field>
|
||||
<field>
|
||||
<name>sms_date</name>
|
||||
</field>
|
||||
</index>
|
||||
</declaration>
|
||||
</table>
|
||||
<table>
|
||||
<name>*dbprefix*ocsms_sendmessage_queue</name>
|
||||
<declaration>
|
||||
<field>
|
||||
<name>id</name>
|
||||
<type>integer</type>
|
||||
<default>0</default>
|
||||
<notnull>true</notnull>
|
||||
<autoincrement>1</autoincrement>
|
||||
<length>10</length>
|
||||
<primary>true</primary>
|
||||
</field>
|
||||
<field>
|
||||
<name>user_id</name>
|
||||
<type>text</type>
|
||||
<notnull>true</notnull>
|
||||
<length>64</length>
|
||||
</field>
|
||||
<field>
|
||||
<name>sms_address</name>
|
||||
<type>text</type>
|
||||
<notnull>true</notnull>
|
||||
<length>64</length>
|
||||
</field>
|
||||
<field>
|
||||
<name>sms_msg</name>
|
||||
<type>text</type>
|
||||
<notnull>true</notnull>
|
||||
<length>2048</length>
|
||||
</field>
|
||||
</declaration>
|
||||
</table>
|
||||
<table>
|
||||
<name>*dbprefix*ocsms_conversation_read_states</name>
|
||||
<declaration>
|
||||
<field>
|
||||
<name>user_id</name>
|
||||
<type>text</type>
|
||||
<notnull>true</notnull>
|
||||
<length>64</length>
|
||||
</field>
|
||||
<field>
|
||||
<name>phone_number</name>
|
||||
<type>text</type>
|
||||
<notnull>true</notnull>
|
||||
<length>64</length>
|
||||
</field>
|
||||
<field>
|
||||
<name>int_date</name>
|
||||
<type>integer</type>
|
||||
<length>32</length>
|
||||
<notnull>true</notnull>
|
||||
</field>
|
||||
<index>
|
||||
<name>sms_conversation_rs_pkey</name>
|
||||
<field>
|
||||
<name>user_id</name>
|
||||
</field>
|
||||
<field>
|
||||
<name>phone_number</name>
|
||||
</field>
|
||||
</index>
|
||||
</declaration>
|
||||
</table>
|
||||
<table>
|
||||
<name>*dbprefix*ocsms_config</name>
|
||||
<declaration>
|
||||
<field>
|
||||
<name>user</name>
|
||||
<type>text</type>
|
||||
<notnull>true</notnull>
|
||||
<length>255</length>
|
||||
</field>
|
||||
<field>
|
||||
<name>key</name>
|
||||
<type>text</type>
|
||||
<notnull>true</notnull>
|
||||
<length>255</length>
|
||||
</field>
|
||||
<field>
|
||||
<name>value</name>
|
||||
<type>text</type>
|
||||
<notnull>false</notnull>
|
||||
<length>10240</length>
|
||||
</field>
|
||||
<index>
|
||||
<name>config_user_key</name>
|
||||
<field>
|
||||
<name>user</name>
|
||||
</field>
|
||||
<field>
|
||||
<name>key</name>
|
||||
</field>
|
||||
</index>
|
||||
</declaration>
|
||||
</table>
|
||||
</database>
|
@ -5,26 +5,35 @@
|
||||
<name>Phone Sync</name>
|
||||
<summary>An app to sync SMS with your cloud</summary>
|
||||
<description>An app to sync SMS with your cloud</description>
|
||||
<licence>agpl</licence>
|
||||
<author homepage="https://www.unix-experience.fr">Loic Blot</author>
|
||||
<version>2.0.1</version>
|
||||
<author>Loic Blot</author>
|
||||
<author>e-alfred</author>
|
||||
<version>2.2.0</version>
|
||||
<licence>agpl</licence>
|
||||
<category>multimedia</category>
|
||||
<category>tools</category>
|
||||
<dependencies>
|
||||
<php min-version="5.6" min-int-size="32"/>
|
||||
<nextcloud min-version="14.0" max-version="14.0" />
|
||||
<nextcloud min-version="18" max-version="20" />
|
||||
</dependencies>
|
||||
|
||||
<ocsid>167289</ocsid>
|
||||
|
||||
<website>https://github.com/nextcloud/ocsms</website>
|
||||
<bugs>https://github.com/nextcloud/ocsms/issues</bugs>
|
||||
<repository type="git">https://github.com/nextcloud/ocsms</repository>
|
||||
<screenshot small-thumbnail="https://raw.githubusercontent.com/nextcloud/ocsms/master/appinfo/screenshots/1-small.png">https://raw.githubusercontent.com/nextcloud/ocsms/master/appinfo/screenshots/1.png</screenshot>
|
||||
|
||||
<fulltextsearch>
|
||||
<provider>OCA\OcSms\Provider\FullTextSearchProvider</provider>
|
||||
</fulltextsearch>
|
||||
<repair-steps>
|
||||
<post-migration>
|
||||
<step>OCA\OcSms\Migration\FixConversationReadStates</step>
|
||||
<step>OCA\OcSms\Migration\FixConversationReadStates</step>
|
||||
</post-migration>
|
||||
</repair-steps>
|
||||
<navigations>
|
||||
<navigation>
|
||||
<id>ocsms</id>
|
||||
<name>Phone Sync</name>
|
||||
<route>ocsms.sms.index</route>
|
||||
<icon>app.svg</icon>
|
||||
</navigation>
|
||||
</navigations>
|
||||
</info>
|
||||
|
@ -43,7 +43,7 @@ $application->registerRoutes($this, array('routes' => array(
|
||||
array('name' => 'api#fetch_messages_count', 'url' => '/api/v2/messages/count', 'verb' => 'GET'), // Android APIv2
|
||||
|
||||
// Android API v3
|
||||
// @TODO
|
||||
array('name' => 'api#generate_sms_test_data', 'url' => '/api/v3/test/generate_sms_data', 'verb' => 'POST'), // Android APIv3
|
||||
|
||||
// Android API v4
|
||||
// @TODO future calls to sending calls recorded on the phone
|
||||
|
@ -229,4 +229,25 @@ class ApiController extends Controller {
|
||||
// @TODO
|
||||
return new JSONResponse(array("messages" => array()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
* @NoCSRFRequired
|
||||
*
|
||||
* @param $smsCount
|
||||
* @param $smsDatas
|
||||
* @return JSONResponse
|
||||
*
|
||||
* produce a bunch of data to test application
|
||||
*/
|
||||
public function generateSmsTestData () {
|
||||
return $this->push(2, array(
|
||||
array("_id" => 702, "type" => 1, "mbox" => 2, "read" => "true",
|
||||
"seen" => "true", "date" => 1654777747, "address" => "+33123456789",
|
||||
"body" => "hello dude"),
|
||||
array("_id" => 685, "type" => 1, "mbox" => 1, "read" => "true",
|
||||
"seen" => "true", "date" => 1654777777, "address" => "+33123456789",
|
||||
"body" => "😀🌍⭐🌎🌔🌒🐕🍖🥂🍻🎮🤸♂️🚇🈲❕📘📚📈🇸🇨🇮🇲"),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +80,21 @@ class SmsController extends Controller {
|
||||
$params = array('user' => $this->userId,
|
||||
'mailboxes' => $mboxes
|
||||
);
|
||||
return new TemplateResponse($this->appName, 'main', $params);
|
||||
$response = new TemplateResponse($this->appName, 'main', $params);
|
||||
$this->addContentSecurityToResponse($response);
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the domain "data:" to the allowed image domains
|
||||
* this function is called by reference
|
||||
*
|
||||
* @param TemplateResponse $response
|
||||
*/
|
||||
private function addContentSecurityToResponse($response) {
|
||||
$csp = new Http\ContentSecurityPolicy();
|
||||
$csp->allowEvalScript(true);
|
||||
$response->setContentSecurityPolicy($csp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3,6 +3,10 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
body.dark #app {
|
||||
color: var(--color-background-dark);
|
||||
}
|
||||
|
||||
#app-navigation {
|
||||
box-sizing: border-box;
|
||||
border-left: 1px solid #ddd;
|
||||
@ -166,6 +170,10 @@
|
||||
float: left;
|
||||
}
|
||||
|
||||
.msg-sent a:link, .msg-sent a:visited, .msg-recv a:link, .msg-recv a:visited {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.msg-date {
|
||||
color: #666;
|
||||
font-style: italic;
|
||||
@ -281,6 +289,13 @@ label {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
img.emoji {
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
margin: 0 .05em 0 .1em;
|
||||
vertical-align: -0.1em;
|
||||
}
|
||||
|
||||
.contact-list-no-contact {
|
||||
padding: 1em;
|
||||
font-size: 1.5em;
|
||||
|
@ -26,7 +26,7 @@ class ConversationStateMapper extends Mapper {
|
||||
public function getLast ($userId) {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->selectAlias($qb->createFunction('MAX(int_date)'), 'mx')
|
||||
->from('ocsms_conversation_read_states')
|
||||
->from('ocsms_conv_r_states')
|
||||
->where($qb->expr()->andX(
|
||||
$qb->expr()->eq('user_id', $qb->createNamedParameter($userId))
|
||||
));
|
||||
@ -42,7 +42,7 @@ class ConversationStateMapper extends Mapper {
|
||||
public function getLastForPhoneNumber ($userId, $phoneNumber) {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->selectAlias($qb->createFunction('MAX(int_date)'), 'mx')
|
||||
->from('ocsms_conversation_read_states')
|
||||
->from('ocsms_conv_r_states')
|
||||
->where($qb->expr()->andX(
|
||||
$qb->expr()->eq('user_id', $qb->createNamedParameter($userId)),
|
||||
$qb->expr()->eq('phone_number', $qb->createNamedParameter($phoneNumber))
|
||||
@ -59,7 +59,7 @@ class ConversationStateMapper extends Mapper {
|
||||
public function setLast ($userId, $phoneNumber, $lastDate) {
|
||||
$this->db->beginTransaction();
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->delete('ocsms_conversation_read_states')
|
||||
$qb->delete('ocsms_conv_r_states')
|
||||
->where($qb->expr()->andX(
|
||||
$qb->expr()->eq('user_id', $qb->createNamedParameter($userId)),
|
||||
$qb->expr()->eq('phone_number', $qb->createNamedParameter($phoneNumber))
|
||||
@ -67,7 +67,7 @@ class ConversationStateMapper extends Mapper {
|
||||
$qb->execute();
|
||||
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$qb->insert('ocsms_conversation_read_states')
|
||||
$qb->insert('ocsms_conv_r_states')
|
||||
->values(array(
|
||||
'user_id' => $qb->createNamedParameter($userId),
|
||||
'phone_number' => $qb->createNamedParameter($phoneNumber),
|
||||
|
@ -132,13 +132,17 @@ class SmsMapper extends Mapper {
|
||||
}
|
||||
$phoneList[$fmtPN][$pn] += 1;
|
||||
}
|
||||
$fpn = PhoneNumberFormatter::format($country, $phoneNumber);
|
||||
if(isset($phoneList[$fpn])){
|
||||
$fpn = $phoneNumber;
|
||||
if(isset($phoneList[$fpn])) {
|
||||
return $phoneList[$fpn];
|
||||
}
|
||||
else {
|
||||
return array();
|
||||
|
||||
$fpn = PhoneNumberFormatter::format($country, $fpn);
|
||||
if (isset($phoneList[$fpn])) {
|
||||
return $phoneList[$fpn];
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
public function getAllMessagesForPhoneNumber ($userId, $phoneNumber, $country, $minDate = 0) {
|
||||
|
BIN
doc/favicon-16x16.png
Normal file
After Width: | Height: | Size: 445 B |
BIN
doc/favicon-32x32.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
60
doc/index.html
Normal file
@ -0,0 +1,60 @@
|
||||
<!-- HTML for static distribution bundle build -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Swagger UI</title>
|
||||
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" >
|
||||
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
|
||||
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
|
||||
<style>
|
||||
html
|
||||
{
|
||||
box-sizing: border-box;
|
||||
overflow: -moz-scrollbars-vertical;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
*,
|
||||
*:before,
|
||||
*:after
|
||||
{
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
body
|
||||
{
|
||||
margin:0;
|
||||
background: #fafafa;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="swagger-ui"></div>
|
||||
|
||||
<script src="./swagger-ui-bundle.js"> </script>
|
||||
<script src="./swagger-ui-standalone-preset.js"> </script>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
// Begin Swagger UI call region
|
||||
const ui = SwaggerUIBundle({
|
||||
url: "https://raw.githubusercontent.com/nextcloud/ocsms/master/doc/swagger.yml",
|
||||
dom_id: '#swagger-ui',
|
||||
deepLinking: true,
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIStandalonePreset
|
||||
],
|
||||
plugins: [
|
||||
SwaggerUIBundle.plugins.DownloadUrl
|
||||
],
|
||||
layout: "StandaloneLayout"
|
||||
})
|
||||
// End Swagger UI call region
|
||||
|
||||
window.ui = ui
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
67
doc/oauth2-redirect.html
Normal file
@ -0,0 +1,67 @@
|
||||
<!doctype html>
|
||||
<html lang="en-US">
|
||||
<body onload="run()">
|
||||
</body>
|
||||
</html>
|
||||
<script>
|
||||
'use strict';
|
||||
function run () {
|
||||
var oauth2 = window.opener.swaggerUIRedirectOauth2;
|
||||
var sentState = oauth2.state;
|
||||
var redirectUrl = oauth2.redirectUrl;
|
||||
var isValid, qp, arr;
|
||||
|
||||
if (/code|token|error/.test(window.location.hash)) {
|
||||
qp = window.location.hash.substring(1);
|
||||
} else {
|
||||
qp = location.search.substring(1);
|
||||
}
|
||||
|
||||
arr = qp.split("&")
|
||||
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';})
|
||||
qp = qp ? JSON.parse('{' + arr.join() + '}',
|
||||
function (key, value) {
|
||||
return key === "" ? value : decodeURIComponent(value)
|
||||
}
|
||||
) : {}
|
||||
|
||||
isValid = qp.state === sentState
|
||||
|
||||
if ((
|
||||
oauth2.auth.schema.get("flow") === "accessCode"||
|
||||
oauth2.auth.schema.get("flow") === "authorizationCode"
|
||||
) && !oauth2.auth.code) {
|
||||
if (!isValid) {
|
||||
oauth2.errCb({
|
||||
authId: oauth2.auth.name,
|
||||
source: "auth",
|
||||
level: "warning",
|
||||
message: "Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"
|
||||
});
|
||||
}
|
||||
|
||||
if (qp.code) {
|
||||
delete oauth2.state;
|
||||
oauth2.auth.code = qp.code;
|
||||
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
|
||||
} else {
|
||||
let oauthErrorMsg
|
||||
if (qp.error) {
|
||||
oauthErrorMsg = "["+qp.error+"]: " +
|
||||
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
|
||||
(qp.error_uri ? "More info: "+qp.error_uri : "");
|
||||
}
|
||||
|
||||
oauth2.errCb({
|
||||
authId: oauth2.auth.name,
|
||||
source: "auth",
|
||||
level: "error",
|
||||
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server"
|
||||
});
|
||||
}
|
||||
} else {
|
||||
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
|
||||
}
|
||||
window.close();
|
||||
}
|
||||
</script>
|
93
doc/swagger-ui-bundle.js
Normal file
1
doc/swagger-ui-bundle.js.map
Normal file
14
doc/swagger-ui-standalone-preset.js
Normal file
1
doc/swagger-ui-standalone-preset.js.map
Normal file
3
doc/swagger-ui.css
Normal file
1
doc/swagger-ui.css.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"sources":[],"names":[],"mappings":"","file":"swagger-ui.css","sourceRoot":""}
|
9
doc/swagger-ui.js
Normal file
1
doc/swagger-ui.js.map
Normal file
58
doc/swagger.yml
Normal file
@ -0,0 +1,58 @@
|
||||
swagger: "2.0"
|
||||
|
||||
info:
|
||||
version: 2.0.0
|
||||
title: OcSMS API
|
||||
description: OcSMS API specification
|
||||
|
||||
schemes:
|
||||
- https
|
||||
host: nextcloud.example.org
|
||||
basePath: /apps/ocsms
|
||||
|
||||
paths:
|
||||
/get/apiversion:
|
||||
get:
|
||||
summary: Retrieve API version
|
||||
description: Returns the current API version.
|
||||
responses:
|
||||
200:
|
||||
description: OcSMS API version
|
||||
schema:
|
||||
required:
|
||||
- version
|
||||
properties:
|
||||
version:
|
||||
type: integer
|
||||
# TODO: complete this
|
||||
/push:
|
||||
post:
|
||||
summary: Push messages to server
|
||||
description: Push a list of messages to the server
|
||||
responses:
|
||||
200:
|
||||
# TODO: complete this
|
||||
/replace:
|
||||
post:
|
||||
summary: Replace messages to server
|
||||
description: Push a list of messages to replace on the server
|
||||
responses:
|
||||
200:
|
||||
# TODO: complete this
|
||||
/get/smsidlist:
|
||||
get:
|
||||
# TODO: complete this
|
||||
/get/lastmsgtime:
|
||||
get:
|
||||
# TODO: complete this
|
||||
/api/v2/phones/list:
|
||||
get:
|
||||
# TODO: complete this
|
||||
/api/v2/messages/{start}/{limit}:
|
||||
get:
|
||||
# TODO: complete this
|
||||
/api/v2/messages/count:
|
||||
get:
|
||||
# Not implemented
|
||||
/api/v4/messages/sendqueue:
|
||||
get:
|
20
gulpfile.js
@ -3,14 +3,18 @@ let concat = require('gulp-concat');
|
||||
let rename = require("gulp-rename");
|
||||
let uglify = require('gulp-uglify-es').default;
|
||||
|
||||
js_files = [
|
||||
'js/devel/app.js',
|
||||
'js/devel/settings.js',
|
||||
'js/devel/contactlist.js',
|
||||
'js/devel/conversation.js',
|
||||
'js/devel/helpers.js',
|
||||
'js/devel/notifications.js'
|
||||
];
|
||||
|
||||
gulp.task("uglify", function () {
|
||||
return gulp.src("js/devel/app.js")
|
||||
.pipe(concat('js/devel/settings.js'))
|
||||
.pipe(concat('js/devel/contactlist.js'))
|
||||
.pipe(concat('js/devel/conversation.js'))
|
||||
.pipe(concat('js/devel/helpers.js'))
|
||||
.pipe(concat('js/devel/notifications.js'))
|
||||
.pipe(rename("app.min.js"))
|
||||
return gulp.src(js_files)
|
||||
.pipe(concat("app.min.js"))
|
||||
.pipe(uglify(/* options */))
|
||||
.pipe(gulp.dest("js/"));
|
||||
});
|
||||
});
|
||||
|
1
js/anchorme.min.js
vendored
Normal file
2
js/app.min.js
vendored
@ -97,11 +97,12 @@ var Conversation = new Vue({
|
||||
// Return (int) msgCount, (str) htmlConversation
|
||||
formatConversation: function (jsondata) {
|
||||
// Improve jQuery performance
|
||||
let buf = false;
|
||||
// Improve JS performance
|
||||
let msgClass = '';
|
||||
let msgCount = 0;
|
||||
let buf = false;
|
||||
// Improve JS performance
|
||||
let msgClass = '';
|
||||
let msgCount = 0;
|
||||
let self = this;
|
||||
let twemojiOptions = { base: OC.generateUrl('/apps/ocsms/js/twemoji/')};
|
||||
|
||||
$.each(jsondata["conversation"], function (id, vals) {
|
||||
if (vals["type"] == 1) {
|
||||
@ -124,7 +125,7 @@ var Conversation = new Vue({
|
||||
'id': id,
|
||||
'type': msgClass,
|
||||
'date': new Date(id * 1),
|
||||
'content': vals['msg']
|
||||
'content': twemoji.parse(anchorme(escapeHTML(vals['msg'])), twemojiOptions)
|
||||
});
|
||||
buf = true;
|
||||
msgCount++;
|
||||
|
@ -26,4 +26,52 @@ function toBool(str) {
|
||||
return false;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function escapeHTML(string) {
|
||||
var str = '' + string
|
||||
var matchHtmlRegExp = /["'&<>]/
|
||||
var match = matchHtmlRegExp.exec(str)
|
||||
|
||||
if (!match) {
|
||||
return str
|
||||
}
|
||||
|
||||
var escape
|
||||
var html = ''
|
||||
var index = 0
|
||||
var lastIndex = 0
|
||||
|
||||
for (index = match.index; index < str.length; index++) {
|
||||
switch (str.charCodeAt(index)) {
|
||||
case 34: // "
|
||||
escape = '"'
|
||||
break
|
||||
case 38: // &
|
||||
escape = '&'
|
||||
break
|
||||
case 39: // '
|
||||
escape = '''
|
||||
break
|
||||
case 60: // <
|
||||
escape = '<'
|
||||
break
|
||||
case 62: // >
|
||||
escape = '>'
|
||||
break
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
if (lastIndex !== index) {
|
||||
html += str.substring(lastIndex, index)
|
||||
}
|
||||
|
||||
lastIndex = index + 1
|
||||
html += escape
|
||||
}
|
||||
|
||||
return lastIndex !== index
|
||||
? html + str.substring(lastIndex, index)
|
||||
: html
|
||||
}
|
||||
|
BIN
js/twemoji/72x72/1f004.png
Normal file
After Width: | Height: | Size: 551 B |
BIN
js/twemoji/72x72/1f0cf.png
Normal file
After Width: | Height: | Size: 923 B |
BIN
js/twemoji/72x72/1f170.png
Normal file
After Width: | Height: | Size: 557 B |
BIN
js/twemoji/72x72/1f171.png
Normal file
After Width: | Height: | Size: 458 B |
BIN
js/twemoji/72x72/1f17e.png
Normal file
After Width: | Height: | Size: 562 B |
BIN
js/twemoji/72x72/1f17f.png
Normal file
After Width: | Height: | Size: 403 B |
BIN
js/twemoji/72x72/1f18e.png
Normal file
After Width: | Height: | Size: 682 B |
BIN
js/twemoji/72x72/1f191.png
Normal file
After Width: | Height: | Size: 561 B |
BIN
js/twemoji/72x72/1f192.png
Normal file
After Width: | Height: | Size: 603 B |
BIN
js/twemoji/72x72/1f193.png
Normal file
After Width: | Height: | Size: 517 B |
BIN
js/twemoji/72x72/1f194.png
Normal file
After Width: | Height: | Size: 495 B |
BIN
js/twemoji/72x72/1f195.png
Normal file
After Width: | Height: | Size: 668 B |
BIN
js/twemoji/72x72/1f196.png
Normal file
After Width: | Height: | Size: 670 B |
BIN
js/twemoji/72x72/1f197.png
Normal file
After Width: | Height: | Size: 640 B |
BIN
js/twemoji/72x72/1f198.png
Normal file
After Width: | Height: | Size: 722 B |
BIN
js/twemoji/72x72/1f199.png
Normal file
After Width: | Height: | Size: 553 B |
BIN
js/twemoji/72x72/1f19a.png
Normal file
After Width: | Height: | Size: 747 B |
BIN
js/twemoji/72x72/1f1e6-1f1e8.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
BIN
js/twemoji/72x72/1f1e6-1f1e9.png
Normal file
After Width: | Height: | Size: 697 B |
BIN
js/twemoji/72x72/1f1e6-1f1ea.png
Normal file
After Width: | Height: | Size: 287 B |
BIN
js/twemoji/72x72/1f1e6-1f1eb.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
js/twemoji/72x72/1f1e6-1f1ec.png
Normal file
After Width: | Height: | Size: 849 B |
BIN
js/twemoji/72x72/1f1e6-1f1ee.png
Normal file
After Width: | Height: | Size: 989 B |
BIN
js/twemoji/72x72/1f1e6-1f1f1.png
Normal file
After Width: | Height: | Size: 662 B |
BIN
js/twemoji/72x72/1f1e6-1f1f2.png
Normal file
After Width: | Height: | Size: 245 B |
BIN
js/twemoji/72x72/1f1e6-1f1f4.png
Normal file
After Width: | Height: | Size: 723 B |
BIN
js/twemoji/72x72/1f1e6-1f1f6.png
Normal file
After Width: | Height: | Size: 481 B |
BIN
js/twemoji/72x72/1f1e6-1f1f7.png
Normal file
After Width: | Height: | Size: 453 B |
BIN
js/twemoji/72x72/1f1e6-1f1f8.png
Normal file
After Width: | Height: | Size: 847 B |
BIN
js/twemoji/72x72/1f1e6-1f1f9.png
Normal file
After Width: | Height: | Size: 205 B |
BIN
js/twemoji/72x72/1f1e6-1f1fa.png
Normal file
After Width: | Height: | Size: 835 B |
BIN
js/twemoji/72x72/1f1e6-1f1fc.png
Normal file
After Width: | Height: | Size: 387 B |
BIN
js/twemoji/72x72/1f1e6-1f1fd.png
Normal file
After Width: | Height: | Size: 230 B |
BIN
js/twemoji/72x72/1f1e6-1f1ff.png
Normal file
After Width: | Height: | Size: 402 B |
BIN
js/twemoji/72x72/1f1e6.png
Normal file
After Width: | Height: | Size: 559 B |
BIN
js/twemoji/72x72/1f1e7-1f1e6.png
Normal file
After Width: | Height: | Size: 652 B |
BIN
js/twemoji/72x72/1f1e7-1f1e7.png
Normal file
After Width: | Height: | Size: 406 B |
BIN
js/twemoji/72x72/1f1e7-1f1e9.png
Normal file
After Width: | Height: | Size: 336 B |
BIN
js/twemoji/72x72/1f1e7-1f1ea.png
Normal file
After Width: | Height: | Size: 233 B |
BIN
js/twemoji/72x72/1f1e7-1f1eb.png
Normal file
After Width: | Height: | Size: 390 B |
BIN
js/twemoji/72x72/1f1e7-1f1ec.png
Normal file
After Width: | Height: | Size: 244 B |
BIN
js/twemoji/72x72/1f1e7-1f1ed.png
Normal file
After Width: | Height: | Size: 411 B |
BIN
js/twemoji/72x72/1f1e7-1f1ee.png
Normal file
After Width: | Height: | Size: 940 B |
BIN
js/twemoji/72x72/1f1e7-1f1ef.png
Normal file
After Width: | Height: | Size: 279 B |
BIN
js/twemoji/72x72/1f1e7-1f1f1.png
Normal file
After Width: | Height: | Size: 978 B |
BIN
js/twemoji/72x72/1f1e7-1f1f2.png
Normal file
After Width: | Height: | Size: 919 B |
BIN
js/twemoji/72x72/1f1e7-1f1f3.png
Normal file
After Width: | Height: | Size: 884 B |
BIN
js/twemoji/72x72/1f1e7-1f1f4.png
Normal file
After Width: | Height: | Size: 666 B |
BIN
js/twemoji/72x72/1f1e7-1f1f6.png
Normal file
After Width: | Height: | Size: 871 B |
BIN
js/twemoji/72x72/1f1e7-1f1f7.png
Normal file
After Width: | Height: | Size: 805 B |
BIN
js/twemoji/72x72/1f1e7-1f1f8.png
Normal file
After Width: | Height: | Size: 419 B |
BIN
js/twemoji/72x72/1f1e7-1f1f9.png
Normal file
After Width: | Height: | Size: 1000 B |
BIN
js/twemoji/72x72/1f1e7-1f1fb.png
Normal file
After Width: | Height: | Size: 270 B |
BIN
js/twemoji/72x72/1f1e7-1f1fc.png
Normal file
After Width: | Height: | Size: 214 B |
BIN
js/twemoji/72x72/1f1e7-1f1fe.png
Normal file
After Width: | Height: | Size: 669 B |
BIN
js/twemoji/72x72/1f1e7-1f1ff.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
js/twemoji/72x72/1f1e7.png
Normal file
After Width: | Height: | Size: 459 B |
BIN
js/twemoji/72x72/1f1e8-1f1e6.png
Normal file
After Width: | Height: | Size: 445 B |
BIN
js/twemoji/72x72/1f1e8-1f1e8.png
Normal file
After Width: | Height: | Size: 706 B |
BIN
js/twemoji/72x72/1f1e8-1f1e9.png
Normal file
After Width: | Height: | Size: 602 B |
BIN
js/twemoji/72x72/1f1e8-1f1eb.png
Normal file
After Width: | Height: | Size: 389 B |
BIN
js/twemoji/72x72/1f1e8-1f1ec.png
Normal file
After Width: | Height: | Size: 356 B |
BIN
js/twemoji/72x72/1f1e8-1f1ed.png
Normal file
After Width: | Height: | Size: 220 B |
BIN
js/twemoji/72x72/1f1e8-1f1ee.png
Normal file
After Width: | Height: | Size: 233 B |
BIN
js/twemoji/72x72/1f1e8-1f1f0.png
Normal file
After Width: | Height: | Size: 961 B |
BIN
js/twemoji/72x72/1f1e8-1f1f1.png
Normal file
After Width: | Height: | Size: 394 B |