Ранее, когда отрабатывался механизм автоматического применения шаблона для публикации списка доступных пользователей при создании нового аккаунта, я упоминал о том, что было бы очень хорошо иметь возможность воздействовать на уже имеющиеся аккаунты, я не только те, что вновь создаются. В Jabberd2 нет такой встроенной возможности. Создадим её сторонними средствами.
Мне показалось интересным сделать это на встроенном в "Bash" языке программирования, обращаясь к СУБД MySQL с помощью оригинального клиента.
И так, с чем мы работаем? С тремя таблицами.
Таблица зарегистрированных аккаунтов:
Tablename: authreg:
username: TEXT;
realm: TINYTEXT;
password: TINYTEXT.
username: TEXT;
realm: TINYTEXT;
password: TINYTEXT.
Таблица "ростеров":
Tablename: roster-items:
collection-owner: TEXT, not NULL;
object-sequence: BIGINT(20), primary key, auto-increment, not NULL;
jid: TEXT;
name: TEXT;
to: TINYINT(4);
from: TINYINT(4);
ask: INTEGER.
collection-owner: TEXT, not NULL;
object-sequence: BIGINT(20), primary key, auto-increment, not NULL;
jid: TEXT;
name: TEXT;
to: TINYINT(4);
from: TINYINT(4);
ask: INTEGER.
Таблица группировки фигурантов "ростеров":
Tablename: roster-groups:
collection-owner: TEXT, not NULL;
object-sequence: BIGINT(20), primary key, auto-increment, not NULL;
jid: TEXT;
group: TEXT.
collection-owner: TEXT, not NULL;
object-sequence: BIGINT(20), primary key, auto-increment, not NULL;
jid: TEXT;
group: TEXT.
Формат файла шаблона должен быть определённого вида, чтобы наш примитивный скрипт разбора переменных не сбоил. Создаём (или изменяем существующий) файл шаблона по адресу "/etc/jabberd/templates/roster.xml" и приводим его к следующему виду:
# cat /etc/jabberd/templates/roster.xml
<query xmlns='jabber:iq:roster'>
<item name='Helpdesk One' jid='one.support@domain.com' subscription='none'><group>Support</group></item>
<item name='Helpdesk Two' jid='two.support@domain.com' subscription='none'><group>Support</group></item>
....
<item name='Helpdesk X' jid='x.support@domain.com' subscription='none'><group>Support</group></item>
<item name='Head of Department One' jid='one.head@domain.com' subscription='none'><group>Management</group></item>
<item name='Head of Department Two' jid='two.head@domain.com' subscription='none'><group>Management</group></item>
....
<item name='Head of Department X' jid='x.head@domain.com' subscription='none'><group>Management</group></item>
<item name='Service personnel One' jid='one.service@domain.com' subscription='none'><group>Service</group></item>
<item name='Service personnel Two' jid='two.service@domain.com' subscription='none'><group>Service</group></item>
....
<item name='Service personnel X' jid='x.service@domain.com' subscription='none'><group>Service</group></item>
</query>
<item name='Helpdesk One' jid='one.support@domain.com' subscription='none'><group>Support</group></item>
<item name='Helpdesk Two' jid='two.support@domain.com' subscription='none'><group>Support</group></item>
....
<item name='Helpdesk X' jid='x.support@domain.com' subscription='none'><group>Support</group></item>
<item name='Head of Department One' jid='one.head@domain.com' subscription='none'><group>Management</group></item>
<item name='Head of Department Two' jid='two.head@domain.com' subscription='none'><group>Management</group></item>
....
<item name='Head of Department X' jid='x.head@domain.com' subscription='none'><group>Management</group></item>
<item name='Service personnel One' jid='one.service@domain.com' subscription='none'><group>Service</group></item>
<item name='Service personnel Two' jid='two.service@domain.com' subscription='none'><group>Service</group></item>
....
<item name='Service personnel X' jid='x.service@domain.com' subscription='none'><group>Service</group></item>
</query>
Для того, чтобы не указывать параметры подключения к СУБД в скриптах, воспользуемся способность клиента брать эти данные из конфигурационных файлов:
# touch /etc/jabberd2/my.cnf
# chown jabberd2:jabberd2 /etc/jabberd2/my.cnf
# chmod go-rwx /etc/jabberd2/my.cnf
# chown jabberd2:jabberd2 /etc/jabberd2/my.cnf
# chmod go-rwx /etc/jabberd2/my.cnf
# cat /etc/jabberd2/my.cnf
[client]
user = jabberd2
password = strongPassword
host = localhost
[mysql]
database = jabberd2
user = jabberd2
password = strongPassword
host = localhost
[mysql]
database = jabberd2
Разработчики Jabberd2 люди с размахом, видимо, не желающие размениваться на такие мелочи, как использование "безопасных" имён в СУБД; потому, часть таковых придётся экранировать. Заковырка в том, что символы экранирования в MySQL конфликтуют с аналогичными символами в языке программирования в "Bash" и нам придётся не особо изящно изворачиваться.
Приступаем:
# touch /etc/jabberd2/templates/public.sh
# chown jabberd2:jabberd2 /etc/jabberd2/templates/public.sh
# chmod u+x /etc/jabberd2/templates/public.sh
# chmod go-rwx /etc/jabberd2/templates/public.sh
# chown jabberd2:jabberd2 /etc/jabberd2/templates/public.sh
# chmod u+x /etc/jabberd2/templates/public.sh
# chmod go-rwx /etc/jabberd2/templates/public.sh
# cat /etc/jabberd2/templates/public.sh
#!/bin/bash
export PATH=/sbin:/bin:/usr/sbin:/usr/bin
# Указываем доменное имя нашего сервера Jabber (XMPP)
REALM="@domain.name"
# Загоняем в переменные требующие экранирования имена и названия
TITEMS="\`roster-items\`"
TGROUPS="\`roster-groups\`"
CCOLLECTIONOWNER="\`collection-owner\`"
CTO="\`to\`"
CFROM="\`from\`"
CGROUP="\`group\`"
# Формируем строку запуска клиента MySQL с соответствующими опциями
MYSQL="mysql --defaults-extra-file=/etc/jabberd2/my.cnf --skip-column-names jabberd2"
# Делаем выборку всех пользователей сервера
RESULT=`$MYSQL -e "SELECT DISTINCT username FROM authreg"`
# Перебираем в цикле пользователей
for I in $RESULT
do
# Запускаем перебор строк файла шаблона, отвечающих условию
cat /etc/jabberd/templates/roster.xml | grep --invert-match '<!--' | grep --ignore-case 'jid=' | while read LINE
do
# Выделяем имя, логин и группу аккаунта, вносимого в "ростер"
NAME=`echo $LINE | awk 'match($0,/ name=\047[A-Za-z0-9!@-\., ]+\047 /) {print substr($0, RSTART, RLENGTH)}' | cut -c 8- | rev | cut -c 3- | rev`
JID=`echo $LINE | awk 'match($0,/ jid=\047[A-Za-z0-9!@-\.]+\047 /) {print substr($0, RSTART, RLENGTH)}' | cut -c 7- | rev | cut -c 3- | rev`
GROUP=`echo $LINE | awk 'match($0,/\074group\076.+\074\/group\076/) {print substr($0, RSTART, RLENGTH)}' | cut -c 8- | rev | cut -c 9- | rev`
if [ "${I}${REALM}" != "$JID" ]
then
# Если вносимый аккаунт не есть он самый, то продолжаем
echo "Success done..."
# Проверяем, нет ли уже в "ростере" вносимого в него аккаунта
CHECK_TITEMS=`$MYSQL -e "SELECT jid FROM $TITEMS WHERE $CCOLLECTIONOWNER='${I}${REALM}' AND jid='$JID'"`
if [ "$CHECK_TITEMS" == "" ]
then
# Вносим в "ростер" новый аккаунт, если его там ещё нет
INSERT_TITEMS=`$MYSQL -e "INSERT INTO $TITEMS ($CCOLLECTIONOWNER, jid, name, $CTO, $CFROM, ask) VALUES ('${I}${REALM}', '$JID', '$NAME', 0, 1, 0)"`
echo "Insert..."
else
# Обновляем парметры аккаунта, если он уже присутствует в "ростере"
UPDATE_TITEMS=`$MYSQL -e "UPDATE $TITEMS SET name='$NAME', $CFROM=1 WHERE $CCOLLECTIONOWNER='${I}${REALM}' AND jid='$JID'"`
echo "Update..."
fi
# Проверяем, нет ли уже в таблице группировки вносимого в него аккаунта
CHECK_TGROUPS=`$MYSQL -e "SELECT jid FROM $TGROUPS WHERE $CCOLLECTIONOWNER='${I}${REALM}' AND jid='$JID' LIMIT 1"`
if [ "$CHECK_TGROUPS" == "" ]
then
# Вносим в таблицу аккаунт, если его там ещё нет
INSERT_TGROUPS=`$MYSQL -e "INSERT INTO $TGROUPS ($CCOLLECTIONOWNER, jid, $CGROUP) VALUES ('${I}${REALM}', '$JID', '$GROUP')"`
echo "Add Group..."
else
# Обновляем параметры аккаунта, если он уже присутствует в таблице группировок
UPDATE_TGROUPS=`$MYSQL -e "UPDATE $TGROUPS SET $CGROUP='$GROUP' WHERE $CCOLLECTIONOWNER='${I}${REALM}' AND jid='$JID'"`
echo "Update Groupe..."
fi
fi
done
done
exit 0
export PATH=/sbin:/bin:/usr/sbin:/usr/bin
# Указываем доменное имя нашего сервера Jabber (XMPP)
REALM="@domain.name"
# Загоняем в переменные требующие экранирования имена и названия
TITEMS="\`roster-items\`"
TGROUPS="\`roster-groups\`"
CCOLLECTIONOWNER="\`collection-owner\`"
CTO="\`to\`"
CFROM="\`from\`"
CGROUP="\`group\`"
# Формируем строку запуска клиента MySQL с соответствующими опциями
MYSQL="mysql --defaults-extra-file=/etc/jabberd2/my.cnf --skip-column-names jabberd2"
# Делаем выборку всех пользователей сервера
RESULT=`$MYSQL -e "SELECT DISTINCT username FROM authreg"`
# Перебираем в цикле пользователей
for I in $RESULT
do
# Запускаем перебор строк файла шаблона, отвечающих условию
cat /etc/jabberd/templates/roster.xml | grep --invert-match '<!--' | grep --ignore-case 'jid=' | while read LINE
do
# Выделяем имя, логин и группу аккаунта, вносимого в "ростер"
NAME=`echo $LINE | awk 'match($0,/ name=\047[A-Za-z0-9!@-\., ]+\047 /) {print substr($0, RSTART, RLENGTH)}' | cut -c 8- | rev | cut -c 3- | rev`
JID=`echo $LINE | awk 'match($0,/ jid=\047[A-Za-z0-9!@-\.]+\047 /) {print substr($0, RSTART, RLENGTH)}' | cut -c 7- | rev | cut -c 3- | rev`
GROUP=`echo $LINE | awk 'match($0,/\074group\076.+\074\/group\076/) {print substr($0, RSTART, RLENGTH)}' | cut -c 8- | rev | cut -c 9- | rev`
if [ "${I}${REALM}" != "$JID" ]
then
# Если вносимый аккаунт не есть он самый, то продолжаем
echo "Success done..."
# Проверяем, нет ли уже в "ростере" вносимого в него аккаунта
CHECK_TITEMS=`$MYSQL -e "SELECT jid FROM $TITEMS WHERE $CCOLLECTIONOWNER='${I}${REALM}' AND jid='$JID'"`
if [ "$CHECK_TITEMS" == "" ]
then
# Вносим в "ростер" новый аккаунт, если его там ещё нет
INSERT_TITEMS=`$MYSQL -e "INSERT INTO $TITEMS ($CCOLLECTIONOWNER, jid, name, $CTO, $CFROM, ask) VALUES ('${I}${REALM}', '$JID', '$NAME', 0, 1, 0)"`
echo "Insert..."
else
# Обновляем парметры аккаунта, если он уже присутствует в "ростере"
UPDATE_TITEMS=`$MYSQL -e "UPDATE $TITEMS SET name='$NAME', $CFROM=1 WHERE $CCOLLECTIONOWNER='${I}${REALM}' AND jid='$JID'"`
echo "Update..."
fi
# Проверяем, нет ли уже в таблице группировки вносимого в него аккаунта
CHECK_TGROUPS=`$MYSQL -e "SELECT jid FROM $TGROUPS WHERE $CCOLLECTIONOWNER='${I}${REALM}' AND jid='$JID' LIMIT 1"`
if [ "$CHECK_TGROUPS" == "" ]
then
# Вносим в таблицу аккаунт, если его там ещё нет
INSERT_TGROUPS=`$MYSQL -e "INSERT INTO $TGROUPS ($CCOLLECTIONOWNER, jid, $CGROUP) VALUES ('${I}${REALM}', '$JID', '$GROUP')"`
echo "Add Group..."
else
# Обновляем параметры аккаунта, если он уже присутствует в таблице группировок
UPDATE_TGROUPS=`$MYSQL -e "UPDATE $TGROUPS SET $CGROUP='$GROUP' WHERE $CCOLLECTIONOWNER='${I}${REALM}' AND jid='$JID'"`
echo "Update Groupe..."
fi
fi
done
done
exit 0
С помощью такого примитивного скрипта мы отобразим шаблон списка публичных аккаунтов на всю базу пользователей сервера Jabberd2 (XMPP). В случае необходимости частого применения этого способа придётся озаботится методикой проверки и перепроверки корректности вносимых данных, результатов работы, автоматизацией и тому подобными вещами. Для разовых случаев применения вполне подойдёт внимательность и резервное копирование перед операцией в качестве средства обеспечения целостности.