1
0
Fork 0
mirror of https://github.com/YunoHost-Apps/movim_ynh.git synced 2024-09-03 19:46:19 +02:00

0.9b ready

This commit is contained in:
src386 2015-09-24 17:11:59 +02:00
commit 1ecce2cb0d
88 changed files with 1683 additions and 1087 deletions

View file

@ -3,12 +3,29 @@ Movim for Yunohost.
Movim is a decentralized social network, written in PHP and HTML5 and based on the XMPP standard protocol : https://movim.eu .
Warning: BETA.
Warning: BETA. *Next release should be 1.0RC*
Current Movim version : 20150824.
You need a "valid" (example: StartSSL) certificate to use Movim, auto-signed is not allowed.
Current Movim version : 0.9 git2015-09-22
**Changelog**
0.9b 2015-09-24
- Update to upstream Movim 0.9 git2015-09-22.
- Add notes in README about public pods & whitelisting.
- script/install now check if path is empty.
- script/remove now delete /etc/php/fpm/pool.d/movim.conf (fix #8).
- script/remove now delete 'movim' user only after Movim service is stopped.
- script/remove now stop php5-fpm in order to remove Movim user.
- script/update now updates php dependancies (composer update).
- conf/movim.service now has a PID and a syslog identifier.
- conf/movim.service starts after mysql.service.
- conf/movim.service is now located in /etc/systemd/system.
- conf/movim.init starts after mysql.
- conf/nginx.conf : proxy_read_timeout and proxy_send_timeout removed (default is 60s).
- conf/php-fpm.conf add timezone parameter.
0.8b 2015-08-24
- Added language selection : ar, de, es, it, ja, nl, ru
- Fix URL in manifest.json (was https://https://...)
@ -79,6 +96,13 @@ Username and password are definied during installation.
* URL rewriting is disabled (experimental feature)
* No SSO auto login
**Public Pod & Whitelisting**
* Public pod = Yes : anyone can connect in your Movim pod using its own JID
* Public pod = No : Whitelist allows only JID from your Yunohost to login*
If you want to allow more domains, connect to yourserver.yourdomain.org/movim/?q=admin then add domains in the whitelist.
**Help**
support@conference.yunohost.org src386_

10
TESTS Normal file
View file

@ -0,0 +1,10 @@
Checklist before pushing to master :
* Installation
* Upgrade
* Remove
* Auto start on boot
* Movim login
* Log output
On Debian 8 x86_64 & Debian 7 armhf.

5
TODO
View file

@ -1,5 +0,0 @@
- proxy_read_timeout
- proxy_send_timeout
- check if path is not empty
- whitelist
- movim.service pid / syslog ?

2
conf/movim.init Executable file → Normal file
View file

@ -1,7 +1,7 @@
#!/bin/sh
### BEGIN INIT INFO
# Provides: movim
# Required-Start: $remote_fs $syslog
# Required-Start: $remote_fs $syslog mysql
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6

View file

@ -1,12 +1,15 @@
[Unit]
Description=Movim daemon
After=nginx.service network.target local-fs.target
After=nginx.service network.target local-fs.target mysql.service
[Service]
User=movim
Type=simple
ExecStart=/usr/bin/php daemon.php https://YHURL YHPORT
WorkingDirectory=YHDIR
StandardOutput=syslog
SyslogIdentifier=movim
PIDFile=/run/movim.pid
[Install]
WantedBy=multi-user.target

View file

@ -27,8 +27,6 @@ location ~ ^PATHTOCHANGE/ws/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_read_timeout 86400s;
proxy_send_timeout 86400s;
proxy_redirect off;
}
}

View file

@ -13,3 +13,4 @@ pm.min_spare_servers = 1
pm.max_spare_servers = 3
chdir = /var/www/movim
php_admin_value[open_basedir] = none
php_admin_value[date.timezone] = "YHTZ"

View file

@ -62,7 +62,8 @@
{
"name": "public_site",
"ask": {
"en": "Public pod ?"
"en": "Public pod ? (see README on github)",
"fr": "Pod public ? (voir README sur github)"
},
"choices": ["Yes", "No"],
"default": "No"

View file

@ -8,6 +8,7 @@ password=$4
language=$5
public_site=$6
port=$7
timezone=`cat /etc/timezone`
# Check domain/path availability
sudo yunohost app checkurl $domain$path -a movim
@ -29,7 +30,21 @@ fi
# Check password not empty
if [[ -z "$password" ]]; then
printf "Error empty admin password, aborting"
printf "Error empty admin password, installation aborted"
exit 1
fi
# Check timezone
if [[ -z "$timezone" ]]; then
printf "Could not detect Timezone, please check /etc/timezone. Installation aborted"
exit 1
else
printf "Detected Timezone $timezone \n"
fi
# Check path not empty
if [[ -z "$path" ]]; then
printf "Error path is empty, installation aborted"
exit 1
fi
@ -75,7 +90,7 @@ sudo su -c "cd $final_path && php mud.php db set" movim
sudo su -c "cd $final_path && php mud.php config locale:$language" movim
sudo su -c "cd $final_path && php mud.php config loglevel:1" movim
sudo su -c "cd $final_path && php mud.php config environment:production" movim
sudo su -c "cd $final_path && php mud.php config timezone:`cat /etc/timezone`" movim
sudo su -c "cd $final_path && php mud.php config timezone:$timezone" movim
sudo su -c "cd $final_path && php mud.php config username:$admin" movim
sudo su -c "cd $final_path && php mud.php config password:`echo -n $password | sha1sum | awk '{print $1}'`" movim
if [ $public_site = "No" ];
@ -91,7 +106,7 @@ sudo sed -i "s@YHPORT@$port@g" ../conf/movim.{service,init}
initcheck=`pgrep -ox systemd`
if [ "$initcheck" = "1" ];
then
sudo cp ../conf/movim.service /lib/systemd/system/
sudo cp ../conf/movim.service /etc/systemd/system/
sudo systemctl enable movim.service
sudo systemctl start movim.service
else
@ -102,6 +117,7 @@ else
fi
# php-fpm configuration
sed -i "s@YHTZ@$timezone@g" ../conf/php-fpm.conf
sudo cp ../conf/php-fpm.conf /etc/php5/fpm/pool.d/movim.conf
# Nginx configuration

View file

@ -3,21 +3,24 @@
db_user=movim
db_name=movim
root_pwd=$(sudo cat /etc/yunohost/mysql)
mysql -u root -p$root_pwd -e "DROP DATABASE $db_name ; DROP USER $db_user@localhost ;"
# Removing executable files and user
sudo userdel movim
sudo rm -rf /var/www/movim
domain=$(sudo yunohost app setting movim domain)
sudo rm -f /etc/nginx/conf.d/$domain.d/movim.conf
#REMOVE INIT
#Stop service and remove init
sudo service php5-fpm stop
sudo /etc/init.d/movim stop
sudo systemctl stop movim.service
sudo systemctl disable movim.service
sudo update-rc.d -f movim remove
sudo rm /etc/init.d/movim
sudo rm /lib/systemd/system/movim.service
sudo rm -f /etc/init.d/movim
sudo rm -f /lib/systemd/system/movim.service
#Drop database, movim files and user.
mysql -u root -p$root_pwd -e "DROP DATABASE $db_name ; DROP USER $db_user@localhost ;"
sudo userdel movim
sudo rm -rf /var/www/movim
domain=$(sudo yunohost app setting movim domain)
sudo rm -f /etc/nginx/conf.d/$domain.d/movim.conf
sudo rm /etc/php5/fpm/pool.d/movim.conf
# Restarting services
sudo service nginx reload
sudo service php5-fpm start

View file

@ -5,6 +5,15 @@ path=$(sudo yunohost app setting movim path)
domain=$(sudo yunohost app setting movim domain)
port=$(sudo yunohost app setting movim port)
public_site=$(sudo yunohost app setting movim public_site)
timezone=`cat /etc/timezone`
# Check timezone
if [[ -z "$timezone" ]]; then
printf "Could not detect Timezone, please check /etc/timezone. Installation aborted"
exit 1
else
printf "Detected Timezone $timezone \n"
fi
# Install Movim files
final_path=/var/www/movim
@ -21,8 +30,7 @@ else
fi
# Update PHP dependencies
sudo su -c "curl -sS https://getcomposer.org/installer | php -- --install-dir=$final_path" movim
sudo su -c "cd $final_path && php composer.phar install" movim
sudo su -c "cd $final_path && php composer.phar update" movim
# Movim configuration
sudo sed -i "s@/ws/@$path/ws/@g" $final_path/app/assets/js/movim_websocket.js
@ -43,11 +51,9 @@ sudo sed -i "s@YHPORT@$port@g" ../conf/movim.{service,init}
initcheck=`pgrep -ox systemd`
if [ "$initcheck" = "1" ];
then
sudo systemctl stop movim.service
sudo systemctl disable movim.service
sudo cp ../conf/movim.service /lib/systemd/system/
sudo systemctl enable movim.service
sudo systemctl start movim.service
sudo rm -f /lib/systemd/system/movim.service
sudo cp ../conf/movim.service /etc/systemd/system/
sudo systemctl daemon-reload
else
sudo /etc/init.d/movim stop
sudo cp ../conf/movim.init /etc/init.d/movim
@ -57,6 +63,7 @@ else
fi
# Update php-fpm configuration
sed -i "s@YHTZ@$timezone@g" ../conf/php-fpm.conf
sudo cp ../conf/php-fpm.conf /etc/php5/fpm/pool.d/movim.conf
# Nginx configuration

View file

@ -47,17 +47,9 @@ class MovimEmoji
}
}
/**
* @desc Prepare the string (add the a to the links and show the smileys)
*
* @param string $string
* @param boolean display large emojis
* @param check the links and convert them to pictures (heavy)
* @return string
*/
function prepareString($string, $large = false, $preview = false) {
function addUrls($string, $preview = false) {
// Add missing links
$string = preg_replace_callback(
return preg_replace_callback(
"/([\w\"'>]+\:\/\/[\w-?&;#+%:~=\.\/\@]+[\w\/])/", function ($match) use($preview) {
if(!in_array(substr($match[0], 0, 1), array('>', '"', '\''))) {
$content = $match[0];
@ -84,6 +76,18 @@ function prepareString($string, $large = false, $preview = false) {
}, $string
);
}
/**
* @desc Prepare the string (add the a to the links and show the smileys)
*
* @param string $string
* @param boolean display large emojis
* @param check the links and convert them to pictures (heavy)
* @return string
*/
function prepareString($string, $large = false, $preview = false) {
$string = addUrls($string, $preview);
// We remove all the style attributes
$string = preg_replace_callback(
@ -94,16 +98,7 @@ function prepareString($string, $large = false, $preview = false) {
// Twitter hashtags
$string = preg_replace_callback(
"/ #[a-zA-Z0-9_-]{3,}/", function ($match) {
return
' <a class="twitter hastag" href="http://twitter.com/search?q='.
urlencode(trim($match[0])).
'&src=hash" target="_blank">'.
trim($match[0]).
'</a>';
}, ' ' . $string
);
"/ #[a-zA-Z0-9_-]{3,}/", function ($match) { return ' <a class="twitter hastag" href="http://twitter.com/search?q='. urlencode(trim($match[0])). '&src=hash" target="_blank">'. trim($match[0]). '</a>'; }, ' ' . $string);
$string = preg_replace_callback(
"/ @[a-zA-Z0-9_-]{3,}/", function ($match) {
return

View file

@ -4,12 +4,14 @@ namespace modl;
class Conference extends Model {
public $jid;
public $conference;
public $name;
public $nick;
protected $conference;
protected $name;
protected $nick;
public $autojoin;
public $status;
public $connected = false;
public function __construct() {
$this->_struct = '
{

View file

@ -31,7 +31,7 @@ class Config extends Model {
"loglevel" :
{"type":"string", "size":16, "mandatory":true },
"timezone" :
{"type":"string", "size":16, "mandatory":true },
{"type":"string", "size":32, "mandatory":true },
"xmppwhitelist" :
{"type":"text" },
"info" :
@ -50,7 +50,7 @@ class Config extends Model {
parent::__construct();
$this->description = __('global.description');
$this->description = 'Description';//__('global.description');
$this->theme = 'material';
$this->locale = 'en';
$this->maxusers = -1;

View file

@ -2,6 +2,8 @@
namespace modl;
use Respect\Validation\Validator;
class Contact extends Model {
public $jid;
@ -158,37 +160,36 @@ class Contact extends Model {
}
public function set($vcard, $jid) {
$this->jid = \echapJid($jid);
$this->__set('jid', \echapJid($jid));
$validate_date = Validator::date('Y-m-d');
if(isset($vcard->vCard->BDAY)
&& (string)$vcard->vCard->BDAY != '')
$this->date = (string)$vcard->vCard->BDAY;
else
$this->date = null;
&& $validate_date->validate($vcard->vCard->BDAY))
$this->__set('date', (string)$vcard->vCard->BDAY);
$this->date = date(DATE_ISO8601, strtotime($this->date));
$this->__set('date', date(DATE_ISO8601, strtotime($this->date)));
$this->name = (string)$vcard->vCard->NICKNAME;
$this->fn = (string)$vcard->vCard->FN;
$this->url = (string)$vcard->vCard->URL;
$this->__set('name', (string)$vcard->vCard->NICKNAME);
$this->__set('fn', (string)$vcard->vCard->FN);
$this->__set('url', (string)$vcard->vCard->URL);
$this->gender = (string)$vcard->vCard->{'X-GENDER'};
$this->marital = (string)$vcard->vCard->MARITAL->STATUS;
$this->__set('gender', (string)$vcard->vCard->{'X-GENDER'});
$this->__set('marital', (string)$vcard->vCard->MARITAL->STATUS);
$this->email = (string)$vcard->vCard->EMAIL->USERID;
$this->__set('email', (string)$vcard->vCard->EMAIL->USERID);
$this->adrlocality = (string)$vcard->vCard->ADR->LOCALITY;
$this->adrpostalcode = (string)$vcard->vCard->ADR->PCODE;
$this->adrcountry = (string)$vcard->vCard->ADR->CTRY;
$this->__set('adrlocality', (string)$vcard->vCard->ADR->LOCALITY);
$this->__set('adrpostalcode', (string)$vcard->vCard->ADR->PCODE);
$this->__set('adrcountry', (string)$vcard->vCard->ADR->CTRY);
if(filter_var((string)$vcard->vCard->PHOTO, FILTER_VALIDATE_URL)) {
$this->photobin = base64_encode(
requestUrl((string)$vcard->vCard->PHOTO, 1));
$this->__set('photobin', base64_encode(
requestUrl((string)$vcard->vCard->PHOTO, 1)));
} else {
$this->photobin = (string)$vcard->vCard->PHOTO->BINVAL;
$this->__set('photobin', (string)$vcard->vCard->PHOTO->BINVAL);
}
$this->description = (string)$vcard->vCard->DESC;
$this->__set('description', (string)$vcard->vCard->DESC);
}
public function createThumbnails() {
@ -250,32 +251,32 @@ class Contact extends Model {
}
public function setTune($stanza) {
$this->tuneartist = (string)$stanza->items->item->tune->artist;
$this->tunelenght = (int)$stanza->items->item->tune->lenght;
$this->tunerating = (int)$stanza->items->item->tune->rating;
$this->tunesource = (string)$stanza->items->item->tune->source;
$this->tunetitle = (string)$stanza->items->item->tune->title;
$this->tunetrack = (string)$stanza->items->item->tune->track;
$this->__set('tuneartist', (string)$stanza->items->item->tune->artist);
$this->__set('tunelenght', (int)$stanza->items->item->tune->lenght);
$this->__set('tunerating', (int)$stanza->items->item->tune->rating);
$this->__set('tunesource', (string)$stanza->items->item->tune->source);
$this->__set('tunetitle', (string)$stanza->items->item->tune->title);
$this->__set('tunetrack', (string)$stanza->items->item->tune->track);
}
public function setVcard4($vcard) {
if(isset($vcard->bday->date))
$this->date = (string)$vcard->bday->date;
if(empty($this->date))
$this->date = null;
$validate_date = Validator::date('Y-m-d');
if(isset($vcard->bday->date)
&& $validate_date->validate($vcard->bday->date))
$this->__set('date', (string)$vcard->bday->date);
$this->name = (string)$vcard->nickname->text;
$this->fn = (string)$vcard->fn->text;
$this->url = (string)$vcard->url->uri;
$this->__set('name', (string)$vcard->nickname->text);
$this->__set('fn', (string)$vcard->fn->text);
$this->__set('url', (string)$vcard->url->uri);
if(isset($vcard->gender))
$this->gender = (string)$vcard->gender->sex->text;
$this->__set('gender ', (string)$vcard->gender->sex->text);
if(isset($vcard->marital))
$this->marital = (string)$vcard->marital->status->text;
$this->__set('marital', (string)$vcard->marital->status->text);
$this->adrlocality = (string)$vcard->adr->locality;
$this->adrcountry = (string)$vcard->adr->country;
$this->adrpostalcode = (string)$vcard->adr->code;
$this->__set('adrlocality', (string)$vcard->adr->locality);
$this->__set('adrcountry', (string)$vcard->adr->country);
$this->__set('adrpostalcode', (string)$vcard->adr->code);
if(isset($vcard->impp)) {
foreach($vcard->impp->children() as $c) {
@ -283,21 +284,20 @@ class Contact extends Model {
switch($key) {
case 'twitter' :
$this->twitter = str_replace('@', '', $value);
$this->__set('twitter', str_replace('@', '', $value));
break;
case 'skype' :
$this->skype = (string)$value;
$this->__set('skype', (string)$value);
break;
case 'ymsgr' :
$this->yahoo = (string)$value;
$this->__set('yahoo', (string)$value);
break;
}
}
}
$this->email = (string)$vcard->email->text;
$this->description = trim((string)$vcard->note->text);
$this->__set('email', (string)$vcard->email->text);
$this->__set('description', trim((string)$vcard->note->text));
}
public function getPlace() {
@ -389,6 +389,26 @@ class Contact extends Model {
}
}
function getAlbum()
{
$uri = str_replace(
' ',
'%20',
'http://ws.audioscrobbler.com/2.0/?method=album.getinfo&api_key=80c1aa3abfa9e3d06f404a2e781e38f9&artist='.
$this->tuneartist.
'&album='.
$this->tunesource.
'&format=json'
);
$json = json_decode(requestURL($uri, 2));
if($json->album) {
$json->album->url = $json->album->image[2]->{'#text'};
return $json->album;
}
}
function toRoster() {
return array(
'jid' => $this->jid,

View file

@ -7,14 +7,14 @@ class Message extends Model {
public $jidto;
public $jidfrom;
public $resource;
protected $resource;
public $type;
public $subject;
public $thread;
public $body;
public $html;
protected $subject;
protected $thread;
protected $body;
protected $html;
public $published;
public $delivered;
@ -66,15 +66,15 @@ class Message extends Model {
$this->jidfrom = $jid[0];
if(isset($jid[1]))
$this->resource = $jid[1];
$this->__set('resource', $jid[1]);
$this->type = 'chat';
if($stanza->attributes()->type) {
$this->type = (string)$stanza->attributes()->type;
}
$this->body = (string)$stanza->body;
$this->subject = (string)$stanza->subject;
$this->__set('body', (string)$stanza->body);
$this->__set('subject', (string)$stanza->subject);
$images = (bool)($this->type == 'chat');
@ -83,7 +83,7 @@ class Message extends Model {
$this->html = \fixSelfClosing($this->html);
$this->html = \prepareString($this->html, false, $images);
} else {*/
$this->html = \prepareString($this->body, false, $images);
// $this->html = \prepareString($this->body, false, $images);
//}
if($stanza->delay)
@ -95,4 +95,15 @@ class Message extends Model {
$this->delivered = gmdate('Y-m-d H:i:s');
}
}
public function convertEmojis()
{
$emoji = \MovimEmoji::getInstance();
$this->body = $emoji->replace($this->body);
}
public function addUrls()
{
$this->body = addUrls($this->body);
}
}

View file

@ -90,8 +90,14 @@ class Postn extends Model {
switch($c->attributes()->type) {
case 'html':
case 'xhtml':
if($c->getName() == 'content') return $c->children()->asXML();
else return (string)$c->asXML();
$dom = new \DOMDocument('1.0', 'utf-8');
$import = dom_import_simplexml($c->children());
if($import == null) {
$import = dom_import_simplexml($c);
}
$element = $dom->importNode($import, true);
$dom->appendChild($element);
return (string)$dom->saveHTML();
break;
case 'text':
default :
@ -109,33 +115,33 @@ class Postn extends Model {
else
$entry = $item;
$this->origin = $from;
$this->__set('origin', $from);
if($node)
$this->node = $node;
$this->__set('node', $node);
else
$this->node = (string)$item->attributes()->node;
$this->__set('node', (string)$item->attributes()->node);
$this->nodeid = (string)$entry->attributes()->id;
$this->__set('nodeid', (string)$entry->attributes()->id);
if($entry->entry->id)
$this->nodeid = (string)$entry->entry->id;
$this->__set('nodeid', (string)$entry->entry->id);
// Get some informations on the author
if($entry->entry->author->name)
$this->aname = (string)$entry->entry->author->name;
$this->__set('aname', (string)$entry->entry->author->name);
if($entry->entry->author->uri)
$this->aid = substr((string)$entry->entry->author->uri, 5);
$this->__set('aid', substr((string)$entry->entry->author->uri, 5));
if($entry->entry->author->email)
$this->aemail = (string)$entry->entry->author->email;
$this->__set('aemail', (string)$entry->entry->author->email);
// Non standard support
if($entry->entry->source && $entry->entry->source->author->name)
$this->aname = (string)$entry->entry->source->author->name;
$this->__set('aname', (string)$entry->entry->source->author->name);
if($entry->entry->source && $entry->entry->source->author->uri)
$this->aid = substr((string)$entry->entry->source->author->uri, 5);
$this->__set('aid', substr((string)$entry->entry->source->author->uri, 5));
$this->title = (string)$entry->entry->title;
$this->__set('title', (string)$entry->entry->title);
// Content
if($entry->entry->summary && (string)$entry->entry->summary != '')
@ -153,23 +159,22 @@ class Postn extends Model {
$content = $summary.$content;
if($entry->entry->updated)
$this->updated = (string)$entry->entry->updated;
$this->__set('updated', (string)$entry->entry->updated);
else
$this->updated = gmdate(DATE_ISO8601);
$this->__set('updated', gmdate(DATE_ISO8601));
if($entry->entry->published)
$this->published = (string)$entry->entry->published;
$this->__set('published', (string)$entry->entry->published);
elseif($entry->entry->updated)
$this->published = (string)$entry->entry->updated;
$this->__set('published', (string)$entry->entry->updated);
else
$this->published = gmdate(DATE_ISO8601);
$this->__set('published', gmdate(DATE_ISO8601));
if($delay)
$this->delay = $delay;
$this->__set('delay', $delay);
$contentimg = $this->setAttachements($entry->entry->link);
// Tags parsing
if($entry->entry->category) {
$this->tags = array();
@ -183,22 +188,24 @@ class Postn extends Model {
}
if(!empty($this->tags))
$this->tags = serialize($this->tags);
$this->__set('tags', serialize($this->tags));
if($contentimg != '')
$content .= '<br />'.$contentimg;
if(!isset($this->commentplace))
$this->commentplace = $this->origin;
$this->__set('commentplace', $this->origin);
$this->content = trim($content);
$this->contentcleaned = prepareString(html_entity_decode($this->content));
$this->__set('content', trim($content));
//$this->__set('contentcleaned', prepareString(html_entity_decode($this->content)));
$purifier = new \HTMLPurifier();
$this->contentcleaned = $purifier->purify(html_entity_decode($this->content));
if($entry->entry->geoloc) {
if($entry->entry->geoloc->lat != 0)
$this->lat = (string)$entry->entry->geoloc->lat;
$this->__set('lat', (string)$entry->entry->geoloc->lat);
if($entry->entry->geoloc->lon != 0)
$this->lon = (string)$entry->entry->geoloc->lon;
$this->__set('lon', (string)$entry->entry->geoloc->lon);
}
}
@ -292,6 +299,14 @@ class Postn extends Model {
return false;
}
public function getUUID() {
if(substr($this->nodeid, 10) == 'urn:uuid:') {
return $this->nodeid;
} else {
return 'urn:uuid:'.generateUUID($this->nodeid);
}
}
public function isMicroblog() {
if($this->node == "urn:xmpp:microblog:0")
return true;

View file

@ -82,35 +82,35 @@ class Presence extends Model {
else
$to = $jid[0];
$this->session = $to;
$this->jid = $jid[0];
$this->__set('session', $to);
$this->__set('jid', $jid[0]);
if(isset($jid[1]))
$this->resource = $jid[1];
$this->__set('resource', $jid[1]);
else
$this->resource = 'default';
$this->__set('resource', 'default');
$this->status = (string)$stanza->status;
$this->__set('status', (string)$stanza->status);
if($stanza->c) {
$this->node = (string)$stanza->c->attributes()->node;
$this->ver = (string)$stanza->c->attributes()->ver;
$this->__set('node', (string)$stanza->c->attributes()->node);
$this->__set('ver', (string)$stanza->c->attributes()->ver);
}
if($stanza->priority)
$this->priority = (string)$stanza->priority;
$this->__set('priority', (string)$stanza->priority);
if((string)$stanza->attributes()->type == 'error') {
$this->value = 6;
$this->__set('value', 6);
} elseif((string)$stanza->attributes()->type == 'unavailable') {
$this->value = 5;
$this->__set('value', 5);
} elseif((string)$stanza->show == 'away') {
$this->value = 2;
$this->__set('value', 2);
} elseif((string)$stanza->show == 'dnd') {
$this->value = 3;
$this->__set('value', 3);
} elseif((string)$stanza->show == 'xa') {
$this->value = 4;
$this->__set('value', 4);
} else {
$this->value = 1;
$this->__set('value', 1);
}
// Specific XEP
@ -118,38 +118,38 @@ class Presence extends Model {
foreach($stanza->children() as $name => $c) {
switch($c->attributes()->xmlns) {
case 'jabber:x:signed' :
$this->publickey = (string)$c;
$this->__set('publickey', (string)$c);
break;
case 'http://jabber.org/protocol/muc#user' :
$this->muc = true;
$this->__set('muc ', true);
if($c->item->attributes()->jid)
$this->mucjid = cleanJid((string)$c->item->attributes()->jid);
$this->__set('mucjid', cleanJid((string)$c->item->attributes()->jid));
else
$this->mucjid = (string)$stanza->attributes()->from;
$this->__set('mucjid', (string)$stanza->attributes()->from);
$this->mucrole = (string)$c->item->attributes()->role;
$this->mucaffiliation = (string)$c->item->attributes()->affiliation;
$this->__set('mucrole', (string)$c->item->attributes()->role);
$this->__set('mucaffiliation', (string)$c->item->attributes()->affiliation);
break;
case 'vcard-temp:x:update' :
$this->photo = true;
$this->__set('photo', true);
break;
}
}
}
if($stanza->delay) {
$this->delay =
$this->__set('delay',
gmdate(
'Y-m-d H:i:s',
strtotime(
(string)$stanza->delay->attributes()->stamp
)
)
;
);
}
if($stanza->query) {
$this->last = (int)$stanza->query->attributes()->seconds;
$this->__set('last', (int)$stanza->query->attributes()->seconds);
}
}

View file

@ -6,13 +6,13 @@ class RosterLink extends Model {
public $session;
public $jid;
public $rostername;
protected $rostername;
public $rosterask;
public $rostersubscription;
public $realname;
protected $realname;
public $groupname;
protected $groupname;
public $chaton;
@ -46,12 +46,13 @@ class RosterLink extends Model {
function set($stanza) {
$this->jid = (string)$stanza->attributes()->jid;
if(isset($stanza->attributes()->name) && (string)$stanza->attributes()->name != '')
$this->rostername = (string)$stanza->attributes()->name;
if(isset($stanza->attributes()->name)
&& (string)$stanza->attributes()->name != '')
$this->__set('rostername', (string)$stanza->attributes()->name);
else
$this->rostername = (string)$stanza->attributes()->jid;
$this->rosterask = (string)$stanza->attributes()->ask;
$this->rostersubscription = (string)$stanza->attributes()->subscription;
$this->groupname = (string)$stanza->group;
$this->__set('rostername', (string)$stanza->attributes()->jid);
$this->__set('rosterask', (string)$stanza->attributes()->ask);
$this->__set('rostersubscription', (string)$stanza->attributes()->subscription);
$this->__set('groupname', (string)$stanza->group);
}
}

View file

@ -4,11 +4,11 @@ namespace modl;
class Subscription extends Model {
public $jid;
public $server;
public $node;
public $subscription;
public $subid;
public $title;
protected $server;
protected $node;
protected $subscription;
protected $subid;
protected $title;
public $description;
public $tags;
public $timestamp;
@ -40,13 +40,13 @@ class Subscription extends Model {
}
function set($jid, $server, $node, $s) {
$this->jid = $jid;
$this->server = $server;
$this->node = $node;
$this->jid = (string)$s->attributes()->jid;
$this->subscription = (string)$s->attributes()->subscription;
$this->subid = (string)$s->attributes()->subid;
$this->tags = serialize(array());
$this->__set('jid', $jid);
$this->__set('server', $server);
$this->__set('node', $node);
$this->__set('jid', (string)$s->attributes()->jid);
$this->__set('subscription', (string)$s->attributes()->subscription);
$this->__set('subid', (string)$s->attributes()->subid);
$this->__set('tags', serialize(array()));
if($this->subid = '')
$this->subid = 'default';

View file

@ -5,6 +5,7 @@
<?php $this->widget('Tabs');?>
<?php $this->widget('About');?>
<?php $this->widget('Help');?>
<?php $this->widget('Caps');?>
</div>
</section>

View file

@ -11,8 +11,8 @@
<meta name="theme-color" content="#1C1D5B" />
<link rel="shortcut icon" href="<?php $this->linkFile('img/favicon.ico');?>" />
<link rel="stylesheet" href="<?php echo BASE_URI; ?>app/assets/js/leaflet.css" />
<script src="<?php echo BASE_URI; ?>app/assets/js/leaflet.js"></script>
<!--<link rel="stylesheet" href="<?php echo BASE_URI; ?>app/assets/js/leaflet.css" />
<script src="<?php echo BASE_URI; ?>app/assets/js/leaflet.js"></script>-->
<script src="<?php echo BASE_URI; ?>app/assets/js/favico.js"></script>
<!-- OTR -->

View file

@ -4,7 +4,7 @@
<ul class="thick divided">
<li class="condensed">
<span class="icon bubble color green"><i class="zmdi zmdi-info"></i></span>
<p>{$c->__('about.info')} <a href="http://www.gnu.org/licenses/agpl-3.0.html">GNU Affero General Public License v3</a>.</p>
<p class="all">{$c->__('about.info')} <a href="http://www.gnu.org/licenses/agpl-3.0.html">GNU Affero General Public License v3</a>.</p>
</li>
<li class="subheader">{$c->__('about.thanks')}</li>
<li class="condensed">
@ -20,7 +20,7 @@
<span class="icon bubble color purple"><i class="zmdi zmdi-flag"></i></span>
<span>{$c->__('about.translators')}</span>
<p>
Thanks to all the translators <a href="https://translations.launchpad.net/movim">translations.launchpad.net/movim</a>
{$c->__('about.translators_text')} <a href="https://www.transifex.com/projects/p/movim/">www.transifex.com/projects/p/movim/</a>
</p>
</li>
<li class="subheader">{$c->__('about.software')}</li>

View file

@ -2,6 +2,7 @@
thanks = Thanks
developers = Developers
translators = Translators
translators_text = "Thanks to all the translators"
software = Software
resources = Resources
api = API

View file

@ -13,7 +13,7 @@ class Account extends WidgetBase
$this->addjs('account.js');
$this->registerEvent('register_changepassword_handle', 'onPasswordChanged');
$this->registerEvent('register_remove_handle', 'onRemoved');
$this->registerEvent('register_get_handle', 'onRegister');
$this->registerEvent('register_get_handle', 'onRegister', 'account');
}
function onPasswordChanged()

View file

@ -10,3 +10,7 @@ var Account = {
Presence_ajaxLogout();
}
}
MovimWebsocket.attach(function() {
Notification.current('account');
});

View file

@ -12,9 +12,9 @@ class AccountNext extends WidgetBase {
$this->registerEvent('register_get_handle', 'onForm');
$this->registerEvent('register_set_handle', 'onRegistered');
$this->registerEvent('register_set_errorconflict', 'onRegisterError');
$this->registerEvent('register_set_errornotacceptable', 'onRegisterNotAcceptable');
$this->registerEvent('register_get_errorserviceunavailable', 'onServiceUnavailable');
$this->registerEvent('register_set_errorconflict', 'onRegisterError', 'accountnext');
$this->registerEvent('register_set_errornotacceptable', 'onRegisterNotAcceptable', 'accountnext');
$this->registerEvent('register_get_errorserviceunavailable', 'onServiceUnavailable', 'accountnext');
}
function display()

View file

@ -12,10 +12,10 @@
</div>
<input
class="button flat oppose"
class="button oppose color"
type="submit"
name="submit"
value="{$c->__('button.submit')}" />
value="{$c->__('button.validate')}" />
</form>
</li>
</ul>

View file

@ -72,6 +72,8 @@ class AdminMain extends WidgetBase
$cd = new \Modl\ConfigDAO();
$config = $cd->get();
$l = Movim\i18n\Locale::start();
$this->view->assign('conf', $cd->get());
$this->view->assign('logs',
array(
@ -96,6 +98,6 @@ class AdminMain extends WidgetBase
}
$this->view->assign('timezones', getTimezoneList());
$this->view->assign('langs', loadLangArray());
$this->view->assign('langs', $l->getList());
}
}

View file

@ -155,7 +155,7 @@
<input
type="submit"
class="button color green oppose"
value="{$c->__('button.submit')}"/>
value="{$c->__('button.save')}"/>
<div class="clear"></div>
</form>
</div>

View file

@ -46,7 +46,7 @@ class AdminTest extends WidgetBase
$config = $cd->get();
$this->view->assign('dbconnected', $md->_connected);
$this->view->assign('dbtype', $supported[$conf['type']]);
$this->view->assign('dbtype', $supported[$config->type]);
$this->view->assign('dbinfos', sizeof($md->check()));
$this->view->assign('websocketurl', $config->websocketurl);
}

View file

@ -34,10 +34,11 @@
</div>
<ul>
<!--
<li class="subheader">
{$c->__('compatibility.info')}
</li>
-->
{if="$dbconnected"}
{if="$dbinfos > 0"}
<li>

View file

@ -8,10 +8,6 @@ class Blog extends WidgetBase {
function display()
{
/*if(!$this->get('f')) {
return;
}*/
if($this->_view == 'grouppublic') {
$from = $this->get('s');
$node = $this->get('n');

View file

@ -28,7 +28,15 @@
{/if}
</li>
{else}
<li class="condensed">
<li class="condensed action">
<div class="action">
<a
href="{$c->route('feed', array($server, $node))}"
target="_blank"
>
<i class="zmdi zmdi-portable-wifi"></i> Atom
</a>
</div>
<span class="icon gray">
<i class="zmdi zmdi-pages"></i>
</span>
@ -93,17 +101,24 @@
</li>
</ul>
</header>
{$attachements = $value->getAttachements()}
<section>
<content>
{if="strlen($value->contentcleaned) < 500 && isset($attachements.pictures)"}
{loop="$attachements.pictures"}
<a href="{$value.href}" class="alternate" target="_blank">
<img class="big_picture" type="{$value.type}" src="{$value.href|urldecode}"/>
</a>
{/loop}
{/if}
{$value->contentcleaned}
</content>
</section>
<footer>
{$attachements = $value->getAttachements()}
<ul class="middle divided spaced">
{if="isset($attachements.links)"}
{loop="$attachements.links"}
{if="substr($value.href, 0, 5) != 'xmpp:'"}
{if="substr($value.href, 0, 5) != 'xmpp:' && filter_var($value.href, FILTER_VALIDATE_URL)"}
<li>
<span class="icon">
<img src="http://icons.duckduckgo.com/ip2/{$value.url.host}.ico"/>
@ -132,7 +147,7 @@
{/loop}
{/if}
</ul>
{if="isset($attachements.pictures)"}
{if="strlen($value->contentcleaned) >= 500 && isset($attachements.pictures)"}
<ul class="flex middle">
{loop="$attachements.pictures"}
<li class="block pic">

View file

@ -30,10 +30,6 @@ class Bookmark extends WidgetBase
{
$this->addcss('bookmark.css');
$this->registerEvent('bookmark', 'onBookmark');
$this->registerEvent('bookmarkerror', 'onBookmarkError');
//$this->registerEvent('mucrole', 'onMucRole');
$this->registerEvent('groupsubscribed', 'onGroupSubscribed');
$this->registerEvent('groupunsubscribed', 'onGroupUnsubscribed');
}
@ -128,16 +124,6 @@ class Bookmark extends WidgetBase
RPC::call('movim_fill', 'bookmarks', $html);
Notification::append(null, $this->__('bookmarks.updated'));
}
/*
function onMucRole($arr)
{
}
*/
function onBookmarkError($error)
{
Notification::append(null, $this->__('bookmarks.error').$error);
}
function ajaxGetBookmark()
{

View file

@ -72,20 +72,23 @@ class Chat extends WidgetBase
&& $message->type != 'groupchat') {
$avatar = $contact->getPhoto('s');
if($avatar == false) $avatar = null;
Notification::append('chat|'.$from, $contact->getTrueName(), $message->body, $avatar, 4);
Notification::append(
'chat|'.$from,
$contact->getTrueName(),
$message->body,
$avatar,
4,
$this->route('chat', $contact->jid)
);
}
RPC::call('movim_fill', $from.'_state', $contact->jid);
// If the message is from me
} /*else {
} else {
// If the message is from me we reset the notif counter
$from = $message->jidto;
$contact = $cd->get();
}*
$me = $cd->get();
if($me == null) {
$me = new \Modl\Contact;
}*/
$n = new Notification;
$n->ajaxClear('chat|'.$from);
}
if(!preg_match('#^\?OTR#', $message->body)) {
RPC::call('Chat.appendMessage', $this->prepareMessage($message));
@ -253,7 +256,7 @@ class Chat extends WidgetBase
}
$m->body = rawurldecode($message);
$m->html = prepareString($m->body, false, true);
//$m->html = prepareString($m->body, false, true);
$m->published = gmdate('Y-m-d H:i:s');
$m->delivered = gmdate('Y-m-d H:i:s');
@ -265,7 +268,7 @@ class Chat extends WidgetBase
$p = new Publish;
$p->setTo($to);
//$p->setHTML($m->html);
$p->setContent(htmlspecialchars($m->body));
$p->setContent($m->body);
if($muc) {
$p->setMuc();
@ -488,7 +491,10 @@ class Chat extends WidgetBase
if(isset($message->html)) {
$message->body = $message->html;
} else {
$message->body = prepareString(htmlentities($message->body , ENT_COMPAT,'UTF-8'));
// We add some smileys...
$message->convertEmojis();
$message->addUrls();
// $message->body = prepareString(htmlentities($message->body , ENT_COMPAT,'UTF-8'));
}
if($message->type == 'groupchat') {

View file

@ -77,14 +77,13 @@ var Chat = {
};
bubble.querySelector('span.user').innerHTML = message.resource;
var conversation = document.getElementById(id);
if(conversation) {
conversation.appendChild(bubble);
}
bubble.querySelector('div').className = '';
} else {
} else if(Chat.left != null) {
if(message.session == message.jidfrom) {
bubble = Chat.right.cloneNode(true);
if(Chat.previous == 'right') {
@ -110,6 +109,7 @@ var Chat = {
if(bubble) {
bubble.querySelector('div.bubble div').innerHTML = message.body;
bubble.querySelector('div.bubble span.info').innerHTML = message.published;
movim_append(id, bubble.outerHTML);
@ -124,6 +124,7 @@ var Chat = {
MovimWebsocket.attach(function() {
var jid = document.querySelector('#chat_widget').dataset.jid;
if(jid) {
MovimTpl.showPanel();
Chat_ajaxGet(jid);
}
});

View file

@ -1,3 +1,7 @@
<div id="chat_widget" {if="$jid"}data-jid="{$jid}"{/if}>
{if="$jid"}
{$c->prepareChat($jid)}
{else}
{$c->prepareEmpty()}
{/if}
</div>

View file

@ -36,7 +36,9 @@ class Config extends WidgetBase
/* We load the user configuration */
$this->user->reload();
$view->assign('languages', loadLangArray());
$l = Movim\i18n\Locale::start();
$view->assign('languages', $l->getList());
$view->assign('me', $this->user->getLogin());
$view->assign('conf', $this->user->getConfig());

View file

@ -271,26 +271,6 @@ class Contact extends WidgetBase
}
}
function getLastFM($contact)
{
$uri = str_replace(
' ',
'%20',
'http://ws.audioscrobbler.com/2.0/?method=album.getinfo&api_key=80c1aa3abfa9e3d06f404a2e781e38f9&artist='.
$contact->tuneartist.
'&album='.
$contact->tunesource.
'&format=json'
);
$json = json_decode(requestURL($uri, 2));
$img = $json->album->image[2]->{'#text'};
$url = $json->album->url;
return array($img, $url);
}
/**
* @brief Validate the jid
*

View file

@ -131,14 +131,6 @@
</li>
{/if}
{if="$contact->description != null && trim($contact->description) != ''"}
<li class="condensed block">
<span class="icon gray"><i class="zmdi zmdi-format-align-justify"></i></span>
<span>{$c->__('general.about')}</span>
<p class="all">{$contact->description}</p>
</li>
{/if}
{if="$contact->mood != null"}
{$moods = unserialize($contact->mood)}
<li class="condensed block">
@ -150,7 +142,16 @@
</p>
</li>
{/if}
{if="$contact->description != null && trim($contact->description) != ''"}
<li class="condensed block large">
<span class="icon gray"><i class="zmdi zmdi-format-align-justify"></i></span>
<span>{$c->__('general.about')}</span>
<p class="all">{$contact->description}</p>
</li>
{/if}
</ul>
<br />
{if="$blog != null"}
<ul class="active">
@ -171,26 +172,25 @@
</ul>
{/if}
{if="$contact->tuneartist || $contact->tunetitle"}
{$album = $contact->getAlbum()}
{if="$album"}
<ul class="flex">
<li class="subheader block large">{$c->__('general.tune')}</li>
{$img_array = $c->getLastFM($contact)}
<li class="
block
{if="$contact->tunetitle"}condensed{/if}
{if="isset($img_array[1]) && $img_array[1] != ''"} action{/if}
action
">
{if="isset($img_array[1]) && $img_array[1] != ''"}
<div class="action">
<a href="{$img_array[1]}" target="_blank">
<a href="{$album->url}" target="_blank">
<i class="zmdi zmdi-radio"></i>
</a>
</div>
{/if}
<span class="icon bubble">
{if="isset($img_array[0]) && $img_array[0] != ''"}
<img src="{$img_array[0]}"/>
{if="isset($album->url)"}
<img src="{$album->url}"/>
{else}
<i class="zmdi zmdi-play-circle-fill"></i>
{/if}
@ -203,7 +203,6 @@
{$contact->tunesource}
{/if}
</span>
{if="$contact->tunetitle"}
<p>{$contact->tunetitle}</p>
{/if}
@ -329,7 +328,7 @@
{/if}
{if="$contactr->rostersubscription == 'none'"}
<span class="icon gray">
<i class="zmdi zmdi-do-not-disturb"></i>
<i class="zmdi zmdi-block"></i>
</span>
<span>{$c->__('subscription.nil')}</span>

View file

@ -196,10 +196,6 @@ class Group extends WidgetBase
$view->assign('node', $node);
$html .= $view->draw('_group_publish', true);
$header = $this->prepareHeader($server, $node);
Header::fill($header);
RPC::call('MovimTpl.fill', '#group_widget.'.stringToUri($server.'_'.$node), $html);
RPC::call('Group.enableVideos');
}
@ -282,14 +278,14 @@ class Group extends WidgetBase
->request();
}
function ajaxGetSubscriptions($server, $node)
function ajaxGetSubscriptions($server, $node, $notify = true)
{
if(!$this->validateServerNode($server, $node)) return;
$r = new GetSubscriptions;
$r->setTo($server)
->setNode($node)
->setSync()
->setNotify($notify)
->request();
}

View file

@ -54,7 +54,7 @@
<li onclick="Group_ajaxGetConfig('{$item->server}', '{$item->node}')">
<span>{$c->__('group.configuration')}</span>
</li>
<li onclick="Group_ajaxGetSubscriptions('{$item->server}', '{$item->node}')">
<li onclick="Group_ajaxGetSubscriptions('{$item->server}', '{$item->node}', true)">
<span>{$c->__('group.subscriptions')}</span>
</li>
<li onclick="Group_ajaxDelete('{$item->server}', '{$item->node}')">

View file

@ -20,11 +20,13 @@
<span class="icon bubble color {$value->node|stringToColor}">{$value->node|firstLetterCapitalize}</span>
{/if}
<h2>
<a href="{$c->route('news', $value->nodeid)}">
{if="$value->title != null"}
{$value->title}
{else}
{$c->__('post.default_title')}
{/if}
</a>
</h2>
<p>
{if="$value->getContact()->getTrueName() != ''"}
@ -47,7 +49,7 @@
<ul class="thin">
{if="isset($attachements.links)"}
{loop="$attachements.links"}
{if="substr($value.href, 0, 5) != 'xmpp:'"}
{if="substr($value.href, 0, 5) != 'xmpp:' && filter_var($value.href, FILTER_VALIDATE_URL)"}
<li>
<span class="icon small"><img src="http://icons.duckduckgo.com/ip2/{$value.url.host}.ico"/></span>
<a href="{$value.href}" class="alternate" target="_blank">
@ -110,7 +112,9 @@
{/if}
<span class="info">{$value->published|strtotime|prepareDate}</span>
<span>
<a href="{$c->route('contact', $value->getContact()->jid)}">
{$value->getContact()->getTrueName()}
</a>
</span>
<p class="all">
{$value->content}

View file

@ -10,7 +10,7 @@ var Groups = {
Group_ajaxGetItems(this.dataset.server, this.dataset.node);
Group_ajaxGetMetadata(this.dataset.server, this.dataset.node);
Group_ajaxGetAffiliations(this.dataset.server, this.dataset.node);
//Group_ajaxGetSubscriptions(this.dataset.server, this.dataset.node);
Group_ajaxGetSubscriptions(this.dataset.server, this.dataset.node, false);
Groups.reset(items);
movim_add_class(this, 'active');
}

View file

@ -32,7 +32,7 @@
<p>{$c->__('chatroom.button')}<br/>movim@conference.movim.eu</p>
</li>
</ul>
<!--
<div class="clear spacetop"></div>
<h2 class="padded_top_bottom">{$c->__('help.faq')}</h2>
@ -71,5 +71,5 @@
</section>
</article>
</div>
</div>-->
</div>

View file

@ -24,9 +24,6 @@ wrong_account = Movim failed to authenticate. You entered wrong data
mechanism = Authentication mechanism not supported by Movim
fail_auth = The XMPP authentification failed
[account]
title = Accounts
[form]
username = My address
password = Password

View file

@ -23,7 +23,7 @@ var Login = {
Login.rememberSession(localStorage.username);
// A fallback security
setTimeout("MovimWebsocket.unregister()", 7000);
setTimeout("MovimWebsocket.unregister()", 20000);
}
},

View file

@ -8,7 +8,7 @@
<div id="form" class="dialog">
<section>
<span class="info">{$c->__('connected')} {$connected} / {$pop}</span>
<span class="info">{$c->__('form.connected')} {$connected} / {$pop}</span>
<h3>{$c->__('page.login')}</h3>
<form
data-action="{$submit}"

View file

@ -46,9 +46,24 @@ class Menu extends WidgetBase
$title = $post->title;
}
if(!$post->isMine()) Notification::append('news', $contact->getTrueName(), $title, $contact->getPhoto('s'), 2);
if(!$post->isMine())
Notification::append(
'news',
$contact->getTrueName(),
$title,
$contact->getPhoto('s'),
2,
$this->route('news', $post->nodeid)
);
} else {
Notification::append('news', $post->title, $post->node, null, 2);
Notification::append(
'news',
$post->title,
$post->node,
null,
2,
$this->route('news', $post->nodeid)
);
}
$this->onStream($count);

View file

@ -29,16 +29,19 @@ class Notification extends WidgetBase
$session = Session::start();
$notifs = $session->get('notifs');
RPC::call('Notification.desktop', $title, $body, $picture);
RPC::call('Notification.desktop', $title, $body, $picture, $action);
$notifs_key = $session->get('notifs_key');
if($notifs_key != null && $key == $notifs_key) return;
if($notifs == null) $notifs = array();
$explode = explode('|', $key);
$first = reset($explode);
if($notifs_key != null && $first == $notifs_key) return;
RPC::call('Notification.android', $title, $body, $picture, $action);
if(array_key_exists($first, $notifs)) {
$notifs[$first]++;
} else {
@ -58,7 +61,7 @@ class Notification extends WidgetBase
}
$n = new Notification;
RPC::call('Notification.snackbar', $n->prepareSnackbar($title, $body, $picture), $time);
RPC::call('Notification.snackbar', $n->prepareSnackbar($title, $body, $picture, $action), $time);
$session->set('notifs', $notifs);
}
@ -121,13 +124,14 @@ class Notification extends WidgetBase
$session->set('notifs_key', $key);
}
function prepareSnackbar($title, $body = false, $picture = false)
function prepareSnackbar($title, $body = null, $picture = null, $action = null)
{
$view = $this->tpl();
$view->assign('title', $title);
$view->assign('body', $body);
$view->assign('picture', $picture);
$view->assign('action', $action);
return $view->draw('_notification', true);
}

View file

@ -1,3 +1,6 @@
{if="isset($action)"}
<a href="{$action}">
{/if}
<ul class="{if="!isset($picture)"}simple{/if}">
<li class="{if="isset($body)"}condensed{/if}">
{if="isset($picture)"}
@ -9,3 +12,6 @@
{/if}
</li>
</ul>
{if="isset($action)"}
</a>
{/if}

View file

@ -75,6 +75,12 @@ var Notification = {
Notification_ajaxCurrent(Notification.notifs_key);
},
toast : function(html) {
// Android notification
if(typeof Android !== 'undefined') {
Android.showToast(html);
return;
}
target = document.getElementById('toast');
if(target) {
@ -88,7 +94,8 @@ var Notification = {
3000);
},
snackbar : function(html, time) {
if(Notification.inhibed == true) return;
if(typeof Android !== 'undefined'
|| Notification.inhibed == true) return;
target = document.getElementById('snackbar');
@ -102,11 +109,26 @@ var Notification = {
},
time*1000);
},
desktop : function(title, body, picture) {
desktop : function(title, body, picture, action) {
if(Notification.inhibed == true
|| Notification.focused) return;
console.log(DesktopNotification);
|| Notification.focused
|| typeof DesktopNotification === 'undefined') return;
console.log(Notification.focused);
var notification = new DesktopNotification(title, { icon: picture, body: body });
if(action !== null) {
notification.onclick = function() {
window.location.href = action;
}
}
},
android : function(title, body, picture, action) {
if(typeof Android !== 'undefined') {
Android.showNotification(title, body, picture, action);
return;
}
}
}
@ -133,6 +155,8 @@ document.onfocus = function() {
window.addEventListener('load', function () {
if(typeof DesktopNotification === 'undefined') return;
DesktopNotification.requestPermission(function (status) {
// This allows to use Notification.permission with Chrome/Safari
if(DesktopNotification.permission !== status) {

View file

@ -8,7 +8,7 @@
margin-right: 0.5em;
border-radius: 1em;
}
/*
#notifs_widget.groupshown li:not(:first-child){
display: none;
}
@ -24,3 +24,4 @@
content: "\f2c0";
display: inline-block;
}
*/

View file

@ -68,7 +68,7 @@
<ul class="middle divided spaced">
{if="isset($attachements.links)"}
{loop="$attachements.links"}
{if="substr($value.href, 0, 5) != 'xmpp:'"}
{if="substr($value.href, 0, 5) != 'xmpp:' && filter_var($value.href, FILTER_VALIDATE_URL)"}
<li>
<span class="icon">
<img src="http://icons.duckduckgo.com/ip2/{$value.url.host}.ico"/>

View file

@ -1,24 +1,12 @@
[post]
news_feed = News Feed
placeholder = Discover and register to the groups you are interested in
preview = Preview
help = Help
help_more = More help
help_manual = Markdown syntax manual
title = Title
content = Content
link = Link
tags = Tags
valid_url = Please enter a valid url
no_content_preview = No content to preview
no_content = No content
published = Post published
deleted = Post deleted
gallery = This picture will be added to your gallery
hot = "What's Hot"
hot_text = Posts recently published in Groups that you are not subscribed (yet)
new = New post
embed_tip = You can also use services like Imgur or Flickr to host your picture and paste the link here.
repost = This is a re-post from %s
repost_profile = See %s profile

View file

@ -29,6 +29,7 @@ class Publish extends WidgetBase
function load()
{
$this->addjs('publish.js');
$this->addcss('publish.css');
$this->registerEvent('pubsub_postpublish_handle', 'onPublish');
$this->registerEvent('pubsub_testpostpublish_handle', 'onTestPublish');
$this->registerEvent('pubsub_testpostpublish_error', 'onTestPublishError');
@ -138,25 +139,29 @@ class Publish extends WidgetBase
{
RPC::call('Publish.disableSend');
if($form->content->value != '') {
$content = Markdown::defaultTransform($form->content->value);
if($form->title->value != '') {
$p = new PostPublish;
$p->setFrom($this->user->getLogin())
->setTo($form->to->value)
->setContent($form->content->value)
->setTitle($form->title->value)
->setNode($form->node->value);
//->setLocation($geo)
//->enableComments()
// Still usefull ? Check line 44
if($form->node->value == 'urn:xmpp:microblog:0') {
$p->enableComments();
}
if($form->title->value != '') {
$p->setTitle($form->title->value);
$content = $content_xhtml = '';
if($form->content->value != '') {
$content = $form->content->value;
$content_xhtml = Markdown::defaultTransform($content);
}
if($form->embed->value != '' && filter_var($form->embed->value, FILTER_VALIDATE_URL)) {
try {
$embed = Embed\Embed::create($form->embed->value);
$p->setLink($form->embed->value);
@ -164,15 +169,25 @@ class Publish extends WidgetBase
$key = key($embed->images);
$p->setImage($embed->images[0]['value'], $embed->title, $embed->images[0]['mime']);
} else {
$content .= $this->prepareEmbed($embed);
$content_xhtml .= $this->prepareEmbed($embed);
}
} catch(Exception $e) {
error_log($e->getMessage());
}
}
$p->setContentXhtml(rawurldecode($content))
->request();
if($content != '') {
$p->setContent($content);
}
if($content_xhtml != '') {
$p->setContentXhtml(rawurldecode($content_xhtml));
}
$p->request();
} else {
RPC::call('Publish.enableSend');
Notification::append(false, $this->__('publish.no_content'));
Notification::append(false, $this->__('publish.no_title'));
}
}
@ -185,6 +200,7 @@ class Publish extends WidgetBase
return;
}
try {
$embed = Embed\Embed::create($url);
$html = $this->prepareEmbed($embed);
@ -195,6 +211,9 @@ class Publish extends WidgetBase
RPC::call('movim_fill', 'preview', $html);
RPC::call('movim_fill', 'gallery', '');
}
} catch(Exception $e) {
error_log($e->getMessage());
}
}
function prepareEmbed($embed)

View file

@ -5,10 +5,7 @@
<input type="text" name="title" placeholder="{$c->__('post.title')}">
<label for="title">{$c->__('post.title')}</label>
</div>
<div>
<textarea name="content" placeholder="{$c->__('post.content')}" onkeyup="movim_textarea_autoheight(this);"></textarea>
<label for="content">{$c->__('post.content')}</label>
</div>
<div>
<input
type="url"
@ -26,6 +23,15 @@
<div id="gallery"></div>
</div>
<div id="enable_content" onclick="Publish.enableContent();">
<input type="text" value="{$c->__('publish.add_text')}"/>
<label>{$c->__('publish.add_text_label')}</label>
</div>
<div id="content_field">
<textarea name="content" placeholder="{$c->__('post.content_text')}" onkeyup="movim_textarea_autoheight(this);"></textarea>
<label for="content">{$c->__('post.content_label')}</label>
</div>
<ul class="middle flex active">
{if="$c->supported('upload')"}
<li class="block large" onclick="Upload_ajaxRequest()">

View file

@ -1,4 +1,4 @@
<q cite="{$embed->url}">
<div class="quote" cite="{$embed->url}">
<ul>
<li>
<span>
@ -17,4 +17,4 @@
</li>
{/if}
</ul>
</q>
</div>

View file

@ -5,22 +5,23 @@ preview = Preview
help = Help
help_more = More help
help_manual = Markdown syntax manual
title = Title
content = Content
content_label = Content
content_text = You can format your content using Markdown
link = Link
tags = Tags
published = Post published
deleted = Post deleted
gallery = This picture will be added to your gallery
hot = "What's Hot"
embed_tip = You can also use services like Imgur or Flickr to host your picture and paste the link here.
[publish]
valid_url = Please enter a valid url
no_content_preview = No content to preview
no_content = No content
no_title = Please provide a title
new = New post
title = Publish
attach = Add a file or a picture to your post
no_publication = You cannot publish a post on this Group
form_filled = Some fields have been filled in. Do you still want to go back and loose their content?
add_text = Click here to add some text to your publication
add_text_label = Add some text

View file

@ -0,0 +1,13 @@
form[name=post] #enable_content > * {
transition: opacity 0.3s ease;
cursor: pointer;
opacity: 0.3;
}
form[name=post] #enable_content:hover > * {
opacity: 1;
}
form[name=post] #content_field {
display: none;
}

View file

@ -23,6 +23,11 @@ var Publish = {
movim_add_class('#button_send', 'disabled');
},
enableContent: function() {
document.querySelector('#enable_content').style.display = 'none';
document.querySelector('#content_field').style.display = 'block';
},
headerBack: function(server, node, ok) {
// We check if the form is filled
if(Publish.checkFilled() && ok == false) {

View file

@ -16,6 +16,7 @@ class Rooms extends WidgetBase
$this->registerEvent('bookmark_set_handle', 'onBookmark');
$this->registerEvent('presence_muc_handle', 'onConnected');
$this->registerEvent('presence_unavailable_handle', 'onDisconnected');
$this->registerEvent('presence_muc_errorconflict', 'onConflict');
}
function onBookmark()
@ -29,6 +30,11 @@ class Rooms extends WidgetBase
$this->refreshRooms();
}
function onConflict()
{
Notification::append(null, $this->__('chatrooms.conflict'));
}
function onDisconnected()
{
// We reset the Chat view
@ -196,9 +202,9 @@ class Rooms extends WidgetBase
array_push($arr,
array(
'type' => 'conference',
'name' => $c->name,
'name' => htmlentities($c->name),
'autojoin' => $c->autojoin,
'nick' => $c->nick,
'nick' => htmlentities($c->nick),
'jid' => $c->conference));
}
@ -237,7 +243,22 @@ class Rooms extends WidgetBase
{
$view = $this->tpl();
$cod = new \modl\ConferenceDAO();
$view->assign('conferences', $cod->getAll());
$list = $cod->getAll();
$connected = array();
foreach($list as $key => $room) {
if($this->checkConnected($room->conference, $room->nick)) {
$room->connected = true;
array_push($connected, $room);
unset($list[$key]);
}
}
$list = array_merge($connected, $list);
$view->assign('conferences', $list);
$view->assign('room', $this->get('r'));
return $view->draw('_rooms', true);

View file

@ -5,11 +5,10 @@
<span class="info">{$conferences|count}</span>
</li>
{loop="$conferences"}
{$connected = $c->checkConnected($value->conference, $value->nick)}
<li data-jid="{$value->conference}"
{if="$value->nick != null"} data-nick="{$value->nick}" {/if}
class="room {if="$connected"}online{/if}">
{if="$connected"}
class="room {if="$value->connected"}online{/if}">
{if="$value->connected"}
<span class="icon small bubble color {$value->name|stringToColor}"><i class="zmdi zmdi-accounts"></i></span>
{else}
<span class="disabled icon small bubble color {$value->name|stringToColor}"><i class="zmdi zmdi-accounts-outline"></i></span>
@ -18,16 +17,17 @@
<span class="second">{$value->conference}</span>
</li>
{/loop}
</ul>
{if="$conferences == null"}
<ul class="thick spaced">
<li class="condensed">
<span class="icon green">
<i class="zmdi zmdi-accounts-outline"></i>
</span>
<p>{$c->__('rooms.empty_text1')} {$c->__('rooms.empty_text2')}</p>
</li>
{/if}
</ul>
{/if}
{else}
{if="$c->getView() == 'room' && $room != false"}
<div class="placeholder icon">

View file

@ -1,7 +1,7 @@
[rooms]
add = Add a chatroom
empty_text1 = "You don't have any chatroom yet."
empty_text2 = Add one by clicking on the add button in the header.
empty_text2 = Add one by clicking on the add button.
[chatrooms]
title = Chatrooms
@ -17,6 +17,7 @@ connected = Connected to the chatroom
disconnected = Disconnected from the chatroom
users = Users in the room
bad_nickname = Please enter a correct nickname (2 to 40 characters)
conflict = Username already taken
[bookmarks]
updated = Bookmarks updated

View file

@ -31,16 +31,16 @@
<!--ng-class="rosterCtrl.getContactClient(myjid.ajiditems)"-- >-->
<div
class="action"
ng-if="myjid.ajiditems.rosterview.tune != '' || myjid.ajiditems.rosterview.type != '' || myjid.ajiditems.rosterview.subscription != 'both'"
ng-if="myjid.ajiditems.rosterview.tune || myjid.ajiditems.rosterview.type != '' || myjid.ajiditems.rosterview.subscription != 'both'"
ng-switch on="myjid.ajiditems.rosterview.type">
<i ng-switch-when="handheld" class="zmdi zmdi-smartphone"></i>
<i ng-switch-when="phone" class="zmdi zmdi-smartphone"></i>
<i ng-switch-when="web" class="zmdi zmdi-globe-alt"></i>
<i ng-switch-when="bot" class="zmdi zmdi-memory"></i>
<i ng-if="myjid.ajiditems.rosterview.tune" class="zmdi zmdi-play-arrow"></i>
<i ng-if="myjid.ajiditems.rosterview.tune" class="zmdi zmdi-play"></i>
<i ng-if="myjid.ajiditems.rosterview.subscription == 'to'" class="zmdi zmdi-arrow-in"></i>
<i ng-if="myjid.ajiditems.rosterview.subscription == 'from'" class="zmdi zmdi-arrow-out"></i>
<i ng-if="myjid.ajiditems.rosterview.subscription == 'none'" class="zmdi zmdi-do-not-disturb"></i>
<i ng-if="myjid.ajiditems.rosterview.subscription == 'none'" class="zmdi zmdi-block"></i>
</div>
<span

View file

@ -11,58 +11,123 @@ class Syndication extends WidgetBase
{
ob_clean();
if(!$this->get('f')) {
return;
}
$from = $this->get('f');
if(filter_var($from, FILTER_VALIDATE_EMAIL)) {
$node = 'urn:xmpp:microblog:0';
} else {
return;
}
$pd = new \modl\PostnDAO();
$cd = new \modl\ContactDAO();
$id = new \Modl\ItemDAO;
$this->view->assign('contact', $cd->get($from, true));
$this->view->assign('uri', Route::urlize('blog',array($from)));
if(isset($from) && isset($node)) {
$messages = $pd->getPublic($from, $node, 10, 0);
$this->view->assign('messages', $messages);
if(!$this->get('s')) {
return;
}
if(isset($messages[0])) {
$from = $this->get('s');
if(filter_var($from, FILTER_VALIDATE_EMAIL)) {
$node = 'urn:xmpp:microblog:0';
$contact = $cd->get($from);
} elseif(!$this->get('n')) {
return;
} else {
$node = $this->get('n');
$item = $id->getItem($from, $node);
}
$messages = $pd->getPublic($from, $node, 10, 0);
header("Content-Type: application/atom+xml; charset=UTF-8");
$this->view->assign('date', date('c'));
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->formatOutput = true;
$feed = $dom->createElementNS('http://www.w3.org/2005/Atom', 'feed');
$dom->appendChild($feed);
$feed->appendChild($dom->createElement('updated', date('c')));
$feed->appendChild($self = $dom->createElement('link'));
$self->setAttribute('rel', 'self');
if($contact != null) {
$feed->appendChild($dom->createElement('title', __('feed.title', $contact->getTrueName())));
$feed->appendChild($author = $dom->createElement('author'));
$author->appendChild($dom->createElement('name', $contact->getTrueName()));
$author->appendChild($dom->createElement('uri', Route::urlize('blog',array($from))));
$feed->appendChild($dom->createElement('logo', $contact->getPhoto('xl')));
$self->setAttribute('href', Route::urlize('feed',array($server)));
}
if($item != null) {
if($item->name) {
$feed->appendChild($dom->createElement('title', $item->name));
} else {
$feed->appendChild($dom->createElement('title', $item->node));
}
if($item->description) {
$feed->appendChild($dom->createElement('subtitle', $item->description));
} else {
$feed->appendChild($dom->createElement('subtitle', $item->server));
}
$self->setAttribute('href', Route::urlize('feed',array($server, $node)));
}
$feed->appendChild($generator = $dom->createElement('generator', 'Movim'));
$generator->setAttribute('uri', 'https://movim.eu');
$generator->setAttribute('version', APP_VERSION);
foreach($messages as $message) {
$feed->appendChild($entry = $dom->createElement('entry'));
if($message->title) {
$entry->appendChild($dom->createElement('title', $message->title));
} else {
$entry->appendChild($dom->createElement('title', __('post.default_title')));
}
$entry->appendChild($dom->createElement('id', $message->getUUID()));
$entry->appendChild($dom->createElement('updated', date('c', strtotime($message->updated))));
$entry->appendChild($content = $dom->createElement('content'));
$content->appendChild($div = $dom->createElementNS('http://www.w3.org/1999/xhtml', 'div'));
$content->setAttribute('type', 'xhtml');
$f = $dom->createDocumentFragment();
$f->appendXML($message->contentcleaned);
$div->appendChild($f);
//$div->appendChild($dom->createCDATASection($message->contentcleaned));
$attachements = $message->getAttachements();
if(isset($attachements['pictures'])) {
foreach($attachements['pictures'] as $value) {
$entry->appendChild($link = $dom->createElement('link'));
$link->setAttribute('rel', 'enclosure');
$link->setAttribute('type', $value['type']);
$link->setAttribute('href', $value['href']);
}
}
function prepareTitle($title)
{
if($title == null)
return '...';
else
return $this->prepareContent($title, true);
if(isset($attachements['files'])) {
foreach($attachements['files'] as $value) {
$entry->appendChild($link = $dom->createElement('link'));
$link->setAttribute('rel', 'enclosure');
$link->setAttribute('type', $value['type']);
$link->setAttribute('href', $value['href']);
}
}
function prepareContent($content, $title = false)
{
if($title)
return cleanHTMLTags($content);
else
return trim(cleanHTMLTags(prepareString($content)));
if(isset($attachements['links'])) {
foreach($attachements['files'] as $value) {
$entry->appendChild($link = $dom->createElement('link'));
$link->setAttribute('rel', 'alternate');
$link->setAttribute('href', $value['href']);
}
}
}
function generateUUID($content)
{
return generateUUID(serialize($content));
}
function prepareUpdated($date)
{
return date('c', strtotime($date));
echo $dom->saveXML();
exit;
}
}

View file

@ -1,43 +0,0 @@
{if="isset($contact)"}
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>{$c->__('feed.title', $contact->getTrueName())}</title>
<updated>{$date}</updated>
<author>
<name>{$contact->getTrueName()}</name>
<uri><![CDATA[{$uri}]]></uri>
</author>
{$link}
<logo>{$contact->getPhoto('xl')}</logo>
<generator uri="http://movim.eu/" version="{#APP_VERSION#}">
Movim
</generator>
<id>urn:uuid:{$uuid}</id>
{if="!empty($messages)"}
{loop="$messages"}
<entry>
<title>
{if="$value->title != null"}
<![CDATA[{$c->prepareTitle($value->title)}]]>
{else}
<![CDATA[{$c->__('post.default_title')}]]>
{/if}
</title>
<id>urn:uuid:{$c->generateUUID($value->content)}</id>
<updated>{$c->prepareUpdated($value->published)}</updated>
<content type="html">
{if="$value->contentcleaned"}
<![CDATA[{$value->contentcleaned}]]>
{else}
<![CDATA[{$value->content|html_entity_decode|prepareString}]]>
{/if}
</content>
</entry>
{/if}
{/loop}
</feed>
{else}
{$c->__('feed.nope_contact')}
{/if}

View file

@ -5,7 +5,6 @@ var Upload = {
init : function() {
document.getElementById('file').addEventListener('change', function(){
console.log(this);
var file = this.files[0];
Upload_ajaxSend({
name: file.name,

View file

@ -154,17 +154,17 @@
<h3 class="block large">{$c->__('accounts.accounts_title')}</h3>
<div class="block">
<input type="text" name="twitter" class="content" value="{$me->twitter}" placeholder="{$c->__('accounts.nickname')}">
<input type="text" name="twitter" class="content" value="{$me->twitter}" placeholder="{$c->__('accounts.twitter')}">
<label for="twitter"><i class="fa fa-twitter"></i> {$c->__('accounts.twitter')}</label>
</div>
<div class="block">
<input type="text" name="skype" class="content" value="{$me->skype}" placeholder="{$c->__('accounts.nickname')}">
<input type="text" name="skype" class="content" value="{$me->skype}" placeholder="{$c->__('accounts.skype')}">
<label for="skype"><i class="fa fa-skype"></i> {$c->__('accounts.skype')}</label>
</div>
<div class="block">
<input type="email" name="yahoo" class="content" value="{$me->yahoo}" placeholder="{$c->__('accounts.accounts_yahoo')}">
<input type="email" name="yahoo" class="content" value="{$me->yahoo}" placeholder="{$c->__('accounts.yahoo')}">
<label for="skype"><i class="fa fa-yahoo"></i> {$c->__('accounts.yahoo')}</label>
</div>

View file

@ -25,9 +25,8 @@ country = Country
accounts_title = Accounts
twitter = Twitter
skype = Skype
yahoo = Yahoo
yahoo = Yahoo Account
accounts_nickname = Nickname
accounts_yahoo = Yahoo Account
[privacy]
privacy_title = Privacy Level

View file

@ -200,9 +200,6 @@ class Bootstrap {
}
private function loadSystem() {
// Loads up all system libraries.
require_once(SYSTEM_PATH . "/i18n/i18n.php");
require_once(SYSTEM_PATH . "Session.php");
require_once(SYSTEM_PATH . "Sessionx.php");
require_once(SYSTEM_PATH . "Utils.php");
@ -219,8 +216,8 @@ class Bootstrap {
require_once(LIB_PATH . "XMPPtoForm.php");
// SDPtoJingle and JingletoSDP lib :)
require_once(LIB_PATH . "SDPtoJingle.php");
require_once(LIB_PATH . "JingletoSDP.php");
//require_once(LIB_PATH . "SDPtoJingle.php");
//require_once(LIB_PATH . "JingletoSDP.php");
}
private function loadHelpers() {
@ -241,7 +238,7 @@ class Bootstrap {
require_once(SYSTEM_PATH . "widget/WidgetBase.php");
require_once(SYSTEM_PATH . "widget/WidgetWrapper.php");
require_once(APP_PATH . "widgets/WidgetCommon/WidgetCommon.php");
//require_once(APP_PATH . "widgets/WidgetCommon/WidgetCommon.php");
require_once(APP_PATH . "widgets/Notification/Notification.php");
}
@ -255,20 +252,23 @@ class Bootstrap {
$cd = new \Modl\ConfigDAO();
$config = $cd->get();
$l = Movim\i18n\Locale::start();
if($user->isLogged()) {
$lang = $user->getConfig('language');
if(isset($lang)) {
loadLanguage($lang);
$l->load($lang);
} else {
// Load default language.
loadLanguage($config->locale);
$l->load($config->locale);
}
}
elseif(isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
loadLanguageAuto();
$l->detect();
$l->loadPo();
}
else {
loadLanguage($config->locale);
$l->load($config->locale);
}
}
@ -321,7 +321,7 @@ class Bootstrap {
if(file_exists(DOCUMENT_ROOT.'/config/db.inc.php')) {
require DOCUMENT_ROOT.'/config/db.inc.php';
} else {
throw new MovimException('Cannot find config/db.inc.php file');
throw new Exception('Cannot find config/db.inc.php file');
}
$db->setConnectionArray($conf);
@ -387,7 +387,7 @@ class Bootstrap {
$s->load();
$user = new User;
$db = modl\Modl::getInstance();
$db = Modl\Modl::getInstance();
$db->setUser($user->getLogin());
}
}

View file

@ -22,6 +22,7 @@
"react/socket-client": "0.4.*@dev",
"forxer/Gravatar": "~1.2",
"respect/validation": "0.8.*"
"respect/validation": "0.8.*",
"ezyang/htmlpurifier": "^4.7"
}
}

View file

@ -9,8 +9,6 @@ use \React\EventLoop\Factory;
use React\Socket\Server as Reactor;
require dirname(__FILE__) . '/vendor/autoload.php';
require dirname(__FILE__) . '/src/Movim/Daemon/Core.php'; // Why ?
require dirname(__FILE__) . '/src/Movim/Daemon/Session.php'; // Why ?
define('DOCUMENT_ROOT', dirname(__FILE__));
require_once(DOCUMENT_ROOT.'/bootstrap.php');

View file

@ -40,9 +40,14 @@
define('DOCUMENT_ROOT', dirname(__FILE__));
require_once(DOCUMENT_ROOT.'/bootstrap.php');
try {
$bootstrap = new Bootstrap();
$bootstrap->boot();
} catch(Exception $e) {
error_log($e->getMessage());
echo 'Oops, something went wrong, please check the log files';
return;
}
$rqst = new FrontController();
$rqst->handle();

View file

@ -31,6 +31,10 @@ $parser = new \Moxl\Parser;
$buffer = '';
function handleSSLErrors($errno, $errstr) {
fwrite(STDERR, colorize(getenv('sid'), 'yellow')." : ".colorize($errstr, 'red')."\n");
}
$stdin_behaviour = function ($data) use (&$conn, $loop, &$buffer, &$connector, &$xmpp_behaviour, &$parser) {
if(substr($data, -1) == "") {
$messages = explode("", $buffer . substr($data, 0, -1));
@ -52,8 +56,8 @@ $stdin_behaviour = function ($data) use (&$conn, $loop, &$buffer, &$connector, &
$port = 5222;
$dns = \Moxl\Utils::resolveHost($msg->host);
if(isset($dns[0]['target']) && $dns[0]['target'] != null) $msg->host = $dns[0]['target'];
if(isset($dns[0]['port']) && $dns[0]['port'] != null) $port = $dns[0]['port'];
if(isset($dns->target) && $dns->target != null) $msg->host = $dns->target;
if(isset($dns->port) && $dns->port != null) $port = $dns->port;
#fwrite(STDERR, colorize('open a socket to '.$domain, 'yellow')." : ".colorize('sent to XMPP', 'green')."\n");
$connector->create($msg->host, $port)->then($xmpp_behaviour);
}
@ -111,7 +115,18 @@ $xmpp_behaviour = function (React\Stream\Stream $stream) use (&$conn, $loop, &$s
|| $message == '<proceed xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>') {
stream_set_blocking($conn->stream, 1);
stream_context_set_option($conn->stream, 'ssl', 'allow_self_signed', true);
#stream_context_set_option($conn->stream, 'ssl', 'verify_peer_name', false);
#stream_context_set_option($conn->stream, 'ssl', 'verify_peer', false);
set_error_handler('handleSSLErrors');
$out = stream_socket_enable_crypto($conn->stream, 1, STREAM_CRYPTO_METHOD_TLS_CLIENT);
restore_error_handler();
if($out !== true) {
$loop->stop();
return;
}
fwrite(STDERR, colorize(getenv('sid'), 'yellow')." : ".colorize('TLS enabled', 'blue')."\n");
$restart = true;
}
@ -137,7 +152,7 @@ $xmpp_behaviour = function (React\Stream\Stream $stream) use (&$conn, $loop, &$s
\RPC::clear();
if(!empty($msg)) {
//[MaJ[MaJ[MaJ[MaI[MaI[MaI[MaI[MaI[MaI[MaI[MaI[MaIecho json_encode($msg)."";
//echo json_encode($msg)."";
echo base64_encode(gzcompress(json_encode($msg), 9))."";
//fwrite(STDERR, colorize(json_encode($msg).' '.strlen($msg), 'yellow')." : ".colorize('sent to browser', 'green')."\n");
}

View file

@ -1,6 +1,9 @@
# French translations for Movim Website package.
# This file is distributed under the same license as the Movim Website package.
# This file was translated from CodingTeam at <http://codingteam.net/>.
#
# Translators:
# Éfrit, 2015
# Jaussoin Timothée <edhelas@movim.eu>, 2015
# Maxime Buquet <tidusx62@gmail.com>, 2015
# Tom <caporaldead@gmail.com>, 2015
#. #-#-#-#-# locales.po (PACKAGE VERSION) #-#-#-#-#
#. extracted from ../app/widgets/About/locales.ini
#. #-#-#-#-# locales.po (PACKAGE VERSION) #-#-#-#-#
@ -91,18 +94,18 @@
#. extracted from ../locales/locales.ini
msgid ""
msgstr ""
"Project-Id-Version: Movim Website\n"
"Project-Id-Version: movim\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-08-20 15:17+0200\n"
"PO-Revision-Date: 2015-06-10 08:09+0000\n"
"Last-Translator: Axelos <axelos@broman.fr>\n"
"Language-Team: \n"
"Language: \n"
"PO-Revision-Date: 2015-08-21 09:30+0000\n"
"Last-Translator: Jaussoin Timothée <edhelas@movim.eu>\n"
"Language-Team: French (France) (http://www.transifex.com/movim/movim/language/fr_FR/)\n"
"Language: fr_FR\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Launchpad-Export-Date: 2015-06-18 21:08+0000\n"
"X-Generator: Launchpad (build 17570)\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Generator: Translate Toolkit 1.12.0\n"
#: [about]thanks
msgid "Thanks"
@ -137,9 +140,8 @@ msgid "Account"
msgstr "Compte"
#: [account]password_change_title
#, fuzzy
msgid "Change my password"
msgstr "Mot de passe incorrect"
msgstr "Changer de mot de passe"
#: [account]password [db]password [credentials]password [form]password
#: [input]password
@ -147,9 +149,8 @@ msgid "Password"
msgstr "Mot de passe"
#: [account]password_confirmation
#, fuzzy
msgid "Password confirmation"
msgstr "%s Configuration"
msgstr "Confirmation du mot de passe"
#: [account]password_changed
msgid "The password has been updated"
@ -157,7 +158,7 @@ msgstr "Le mot de passe a été mis à jour"
#: [account]password_not_valid
msgid "Please provide a valid password (6 characters minimum)"
msgstr "Veuillez entrer un mot de passe valide (6 lettres minimum)"
msgstr "Veuillez entrer un mot de passe valide (6 caractères minimum)"
#: [account]password_not_same
msgid "The provided passwords are not the same"
@ -168,17 +169,16 @@ msgid "Delete my account"
msgstr "Supprimer mon compte"
#: [account]delete
#, fuzzy
msgid "Delete your account"
msgstr "Supprimer mon compte"
msgstr "Supprimer votre compte"
#: [account]delete_text
msgid "You will delete your XMPP account and all the relative information linked to it (profile, contacts and publications)."
msgstr "Vous allez supprimer votre compte XMPP ainsi que l'ensemble des informations liés à celui-ci (profil, contacts et billets)."
msgstr "Vous allez supprimer votre compte XMPP ainsi que lensemble des informations qui y sont liées (profil, contacts et billets)."
#: [account]delete_text_confirm
msgid "Are you sure that you want to delete it ?"
msgstr "Êtes-vous sûr de vouloir le supprimer?"
msgstr "Êtes-vous sûr de vouloir le supprimer?"
#: [account]gateway_title
msgid "Gateway"
@ -198,11 +198,11 @@ msgstr "sur"
#: [create]successfull
msgid "Your acccount has been successfully registered"
msgstr "Votre compte a été correctement enregistré"
msgstr "Compte créé avec succès"
#: [create]loading
msgid "Loading"
msgstr "Chargement en cours"
msgstr "Chargement"
#: [error]not_acceptable
msgid "Not Acceptable"
@ -210,11 +210,11 @@ msgstr "Non acceptable"
#: [error]service_unavailable
msgid "The registration system of this server is currently unavailable"
msgstr "Le système denregistrement de ce serveur est actuellement indisponible"
msgstr "Le système dinscription de ce serveur est actuellement indisponible"
#: [oob]about
msgid "This server use an external system for the registration, please click on the following URL."
msgstr "Ce serveur utilise un service externe pour enregistrer les nouveaux utilisateurs, veuillez sil vous plaît cliquer sur le lien suivant."
msgstr "Ce serveur utilise un service externe pour enregistrer les nouveaux utilisateurs, cliquer sur lien suivant pour y accéder."
#: [adhoc]title
msgid "Actions"
@ -226,7 +226,7 @@ msgstr "Base de données"
#: [db]connect_error
msgid "Modl wasn't able to connect to the database"
msgstr "Modl na pas été en mesure de se connecter à la base de données"
msgstr "Modl na pas pu se connecter à la base de données"
#: [db]connect_success
msgid "Movim is connected to the database"
@ -246,7 +246,7 @@ msgstr "Type de base de données"
#: [db]username [credentials]username [input]username
msgid "Username"
msgstr "Identifiant"
msgstr "Nom dutilisateur"
#: [db]host
msgid "Host"
@ -257,9 +257,8 @@ msgid "Port"
msgstr "Port"
#: [db]name
#, fuzzy
msgid "Database sName"
msgstr "Nom de la base de données"
msgstr ""
#: [admin]general
msgid "General Settings"
@ -275,7 +274,7 @@ msgstr "Langue par défaut"
#: [general]log_verbosity
msgid "Log verbosity"
msgstr "Niveau de détail des journaux"
msgstr "Niveau de détails des journaux"
#: [general]timezone
msgid "Server Timezone"
@ -291,7 +290,7 @@ msgstr "Configuration du WebSocket"
#: [websocket]info
msgid "Enter here a valid WebSocket URI in the form"
msgstr "Veuillez saisir une URI WebSocket valide dans le formulaire"
msgstr "Veuillez saisir une URI du WebSocket valide dans le formulaire"
#: [websocket]label
msgid "WebSocket URI"
@ -299,7 +298,7 @@ msgstr "URI du WebSocket"
#: [websocket]save_info
msgid "If you change the URI, please restart the daemon to reload the configuration"
msgstr "Si vous changez lURI, veuillez relancer le démon afin de prendre en compte la configuration"
msgstr "Veuillez relancer le démon si vous changer lURI, afin de prendre en compte la configuration"
#: [websocket]publics
msgid "Public WebSockets"
@ -311,7 +310,7 @@ msgstr "Identification de ladministrateur"
#: [credentials]info
msgid "Change the default credentials admin/password"
msgstr "Modifiez les paramètres didentification admin/password"
msgstr "Modifiez les paramètres didentification admin/mot de passe"
#: [credentials]re_password
msgid "Retype password"
@ -323,7 +322,7 @@ msgstr "Serveurs XMPP : Liste blanche"
#: [whitelist]info1
msgid "If you want to specify a list of authorized XMPP servers on your Movim pod and forbid the connection on all the others please put their domain name here, with comma (ex: movim.eu,jabber.fr)"
msgstr "Si vous souhaitez établir une liste de serveurs XMPP autorisés sur votre pod Movim et interdire la connexion à tous les autres, veuillez saisir la liste de leurs noms de domaine, séparés par une virgule (ex : movim.eu, jabber.fr)."
msgstr "Si vous souhaitez établir une liste de serveurs XMPP autorisés sur votre pod Movim et interdire la connexion à tous les autres, saisissez la liste de leurs noms de domaine, séparés par une virgule (ex : movim.eu, jabber.fr)."
#: [whitelist]info2
msgid "Leave this field blank if you allow the access to all the XMPP accounts."
@ -334,7 +333,6 @@ msgid "List of whitelisted XMPP servers"
msgstr "Liste blanche des serveurs XMPP"
#: [information]title
#, fuzzy
msgctxt "[information]title"
msgid "Information Message"
msgstr "Message dinformation"
@ -348,12 +346,10 @@ msgid "This message will be displayed on the login page"
msgstr "Ce message sera affiché sur la page de connexion."
#: [information]info2
#, fuzzy
msgid "Leave this field blank if you dont want to show any message."
msgstr "Laissez ce champ vide si vous ne voulez afficher aucun message."
#: [information]label
#, fuzzy
msgctxt "[information]label"
msgid "Information Message"
msgstr "Message dinformation"
@ -372,11 +368,11 @@ msgstr "Journal système et fichiers"
#: [rewrite]title
msgid "URL Rewriting"
msgstr "Réécriture d'URL"
msgstr "Réécriture dURL"
#: [rewrite]info
msgid "The URL Rewriting can be enabled"
msgstr "La réécriture d'URL peut être activée"
msgstr "La réécriture dURL peut être activée"
#: [admin]compatibility
msgid "General Overview"
@ -384,7 +380,7 @@ msgstr "Aperçu général"
#: [compatibility]info
msgid "Movim has found some issues or things that need to be fixed or improved"
msgstr "Movim a rencontré des problèmes ou des choses qui doivent être corrigés ou améliorés"
msgstr "Movim a rencontré des problèmes ou des soucis qui doivent être corrigés ou améliorés"
#: [compatibility]php1
msgid "Update your PHP-Version: %s"
@ -407,7 +403,6 @@ msgid "Install the php5-gd library"
msgstr "Installez la librairie php5-gd"
#: [compatibility]rights
#, fuzzy
msgid "Read and write rights for the webserver in Movims root directory"
msgstr "Droits de lecture et décriture pour le serveur web dans le dossier racine de Movim"
@ -421,11 +416,11 @@ msgstr "La base de données doit être mise à jour, allez dans son panneau pour
#: [compatibility]websocket
msgid "WebSocket connection error, check if the Movim Daemon is running and is reachable"
msgstr ""
msgstr "Erreur de connexion WebSocket, vérifiez si le démon Movim est en cours dexécution et sil est joignable"
#: [compatibility]xmpp_websocket
msgid "XMPP Websocket connection error, please check the validity of the URL given in the General Configuration"
msgstr "Erreur de connexion XMPP Websocket, s'il vous plaît vérifier la validité de l'URL donnée dans la configuration générale"
msgstr "Erreur de connexion XMPP Websocket, veuillez vérifier la validité de lURL donnée dans la configuration générale"
#: [schema]browser
msgid "Browser"
@ -433,7 +428,7 @@ msgstr "Navigateur"
#: [schema]movim
msgid "Movim Core"
msgstr ""
msgstr "Cœur de Movim"
#: [schema]daemon
msgid "Movim Daemon"
@ -449,11 +444,11 @@ msgstr "Vous pouvez enregistrer ici votre pod sur %slAPI officielle%s et êtr
#: [api]register
msgid "Your pod is not registered on the API"
msgstr "Votre pod nest pas enregistré sur lAPI"
msgstr "Votre pod nest pas enregistré dans lAPI"
#: [api]registered
msgid "Your pod is registered on the API"
msgstr "Votre pod est enregistré sur lAPI"
msgstr "Votre pod est enregistré dans lAPI"
#: [api]wait
msgid "Your pod is not yet validated"
@ -481,7 +476,7 @@ msgstr "Utiliser"
#: [avatar]webcam
msgid "Webcam"
msgstr "Caméra"
msgstr "Webcam"
#: [avatar]cheese
msgid "Cheese !"
@ -505,7 +500,7 @@ msgstr "Flux de %s"
#: [blog]empty
msgid "This user has not posted anything right now"
msgstr "Cet utilisateur n'a rien publié pour le moment"
msgstr "Cet utilisateur na rien publié pour le moment"
#: [title]conferences
msgid "Conferences"
@ -524,7 +519,6 @@ msgid "Chat Room ID"
msgstr "Identifiant du salon"
#: [chatroom]name
#, fuzzy
msgctxt "[chatroom]name"
msgid "Name"
msgstr "Nom"
@ -550,7 +544,6 @@ msgid "Bookmarks updated"
msgstr "Signets mis à jour"
#: [bookmarks]error
#, fuzzy
msgid "An error occured :"
msgstr "Une erreur sest produite : "
@ -567,7 +560,6 @@ msgid "URL"
msgstr "URL"
#: [url]name
#, fuzzy
msgctxt "[url]name"
msgid "Name"
msgstr "Nom"
@ -614,7 +606,7 @@ msgstr "Discuter avec vos contacts"
#: [chat]frequent [chats]frequent
msgid "Frequent contacts"
msgstr "Contacts fréquent"
msgstr "Contacts fréquents"
#: [chatroom]members
msgid "Members"
@ -645,14 +637,12 @@ msgid "Subject changed"
msgstr "Sujet mis à jour"
#: [chats]empty_title
#, fuzzy
msgid "No chats yet..."
msgstr "Pas de commentaires pour le moment"
msgstr "Pas de discussions pour le moment"
#: [chats]empty
#, fuzzy
msgid "Open a new conversation by clicking on the plus button bellow or visit the Contacts page."
msgstr "Commencez une nouvelle conversation en cliquant sur le bouton plus ci-dessous"
msgstr "Commencez une nouvelle conversation en cliquant sur le bouton plus ci-dessous ou visitez la page Contacts."
#: [chats]add
msgid "Chat with a contact"
@ -707,7 +697,6 @@ msgid "Appearence"
msgstr "Apparence"
#: [config]info
#, fuzzy
msgid "This configuration is shared wherever you are connected"
msgstr "Cette configuration est partagée partout où vous vous connectez!"
@ -832,44 +821,40 @@ msgid "Last public post"
msgstr "Derniers billets public"
#: [subscription]to
#, fuzzy
msgid "You can see this contact status"
msgstr "Pas de flux public pour ce contact"
msgstr "Vous pouvez voir l'état de ce contact"
#: [subscription]to_button
msgid "Share my status"
msgstr ""
msgstr "Partager mon état"
#: [subscription]to_text
msgid "But this contact cannot see yours"
msgstr ""
msgstr "Mais ce contact ne peux pas voir le votre"
#: [subscription]from
#, fuzzy
msgid "You are not subscribed to this contact"
msgstr "Vous allez vous désinscrire de ce Groupe."
msgstr "Vous nêtes pas abonné à ce contact"
#: [subscription]from_button
#, fuzzy
msgid "Ask to subscribe"
msgstr "%s souscrits"
msgstr "Demander pour sabonner"
#: [subscription]from_text
msgid "But this contact can still see if you are online"
msgstr ""
msgstr "Mais ce contact peut tout de même voir votre présence en ligne"
#: [subscription]nil
#, fuzzy
msgid "No subscriptions"
msgstr "Abonnements"
msgstr ""
#: [subscription]nil_button
msgid "Invite"
msgstr ""
msgstr "Inviter"
#: [subscription]nil_text
msgid "This contact is in your contact list but there is no subscriptions between the two accounts"
msgstr ""
msgstr "Ce contact est dans votre liste de contacts mais il ny a pas dabonnements entre les deux comptes"
#: [group]subscribe
msgid "Subscribe"
@ -905,7 +890,7 @@ msgstr "Êtes-vous sûr?"
#: [group]empty_text
msgid "Discover, follow and share"
msgstr "Découvrire, suivre et partager"
msgstr "Découvrir, suivre et partager"
#: [group]empty
msgid "Something bad happened to this group"
@ -929,16 +914,15 @@ msgstr "Il semblerait que que groupe n'existe plus. Souhaitez-vous le supprimer
#: [group]counter
msgid "%s groups on this server"
msgstr ""
msgstr "%s groupes sur ce serveur"
#: [group]subscriptions [statistics]subscriptions
msgid "Subscriptions"
msgstr "Abonnements"
#: [group]servers
#, fuzzy
msgid "Groups servers"
msgstr "Groupes"
msgstr ""
#: [group]search_server
msgid "Search for a new server"
@ -1002,11 +986,11 @@ msgstr "Groupe supprimé avec succès"
#: [groups]name_error
msgid "Please provide a valid group name (4 characters minimum)"
msgstr ""
msgstr "Merci d'entrer un nom de groupe valide (4 caractères minimum)"
#: [groups]no_creation
msgid "You cannot create a new Group on this server"
msgstr ""
msgstr "Aucun formulaire de création de compte na été trouvé sur le serveur"
#: [groups]sub
msgid "%s subscribers"
@ -1017,9 +1001,8 @@ msgid "%s posts"
msgstr "%s billets"
#: [groups]disco_error
#, fuzzy
msgid "This server doesn't exists"
msgstr "Ce serveur héberge %s comptes"
msgstr ""
#: [menu]all
msgid "All"
@ -1030,14 +1013,12 @@ msgid "Refresh all the streams"
msgstr "Rafraîchir tous les flux"
#: [roster]search
#, fuzzy
msgid "Search in your contacts"
msgstr "Discuter avec vos contacts"
msgstr "Chercher dans vos contacts "
#: [hello]active_contacts
#, fuzzy
msgid "Active contacts"
msgstr "Vos contacts"
msgstr "Contacts actifs"
#: [hello]chat
msgid "Go on the Chat page"
@ -1053,7 +1034,7 @@ msgstr "Lire tous ces articles sur la page Actualité"
#: [hello]blog_title
msgid "Visit your public blog"
msgstr "Aller sur votre blog publique"
msgstr "Aller sur votre blog public"
#: [hello]blog_text
msgid "See your public posts and share them with all your contacts"
@ -1169,7 +1150,7 @@ msgstr "Mettre à jour ma position"
#: [login_anonymous]bad_username
msgid "Bad nickname (between 4 and 40 characters)"
msgstr ""
msgstr "Mauvais surnom (entre 4 et 40 caractères)"
#: [error]username
msgid "Wrong username"
@ -1208,7 +1189,6 @@ msgid "Account successfully created"
msgstr "Compte créé avec succès"
#: [error]xmpp_unauthorized
#, fuzzy
msgctxt "[error]xmpp_unauthorized"
msgid "Your XMPP server is unauthorized"
msgstr "Votre compte XMPP nest pas autorisé à se connecter"
@ -1246,7 +1226,6 @@ msgid "Invalid password format"
msgstr "Mot de passe non valide"
#: [error]unauthorized
#, fuzzy
msgctxt "[error]unauthorized"
msgid "Your XMPP server is unauthorized"
msgstr "Votre compte XMPP nest pas autorisé à se connecter"
@ -1300,12 +1279,10 @@ msgid "Population"
msgstr "Population"
#: [menu]empty_title
#, fuzzy
msgid "No news yet..."
msgstr "Pas de commentaires pour le moment"
#: [menu]empty
#, fuzzy
msgid "Welcome on your news feed, here you will see all the posts published by your contacts and in the groups you have subscribed."
msgstr "Bienvenue sur flux dactualité, ici vous verrez tous les billets publiés dans les groupes auxquels vous vous êtes abonnés."
@ -1439,16 +1416,15 @@ msgstr "Vous pouvez également utiliser des services comme Imgur ou Flickr pour
#: [post]repost
msgid "This is a re-post from %s"
msgstr ""
msgstr "Ceci est une republication de %s"
#: [post]repost_profile
msgid "See %s profile"
msgstr ""
msgstr "Voir le profil de %s"
#: [post]public
#, fuzzy
msgid "Publish this post publicly?"
msgstr "Publier ce billet sur votre flux public?"
msgstr ""
#: [post]blog_add
msgid "Post published on your blog"
@ -1496,11 +1472,11 @@ msgstr "Présence"
#: [status]online
msgid "Online with Movim"
msgstr ""
msgstr "En ligne avec Movim"
#: [publish]title
msgid "Publish"
msgstr ""
msgstr "Publier"
#: [publish]attach
msgid "Add a file or a picture to your post"
@ -1508,11 +1484,11 @@ msgstr ""
#: [publish]no_publication
msgid "You cannot publish a post on this Group"
msgstr ""
msgstr "Vous ne pouvez pas publier de billet sur ce groupe"
#: [publish]form_filled
msgid "Some fields have been filled in. Do you still want to go back and loose their content?"
msgstr ""
msgstr "Certains champs ont été remplis. Êtes-vous sûr de vouloir revenir en arrière et de perdre le contenu déjà saisi ?"
#: [public_groups]shared
msgid "Shared"
@ -1548,31 +1524,31 @@ msgstr "Utilisateurs du salon"
#: [chatrooms]bad_nickname
msgid "Please enter a correct nickname (2 to 40 characters)"
msgstr ""
msgstr "Merci d'entrer un surnom valide (entre 2 et 40 caractères)"
#: [room]anonymous_title
msgid "Public chatroom"
msgstr ""
msgstr "Salon public"
#: [room]no_room
msgid "Please provide a room address"
msgstr ""
msgstr "Merci d'entrer l'adresse d'un salon"
#: [room]anonymous_text1
msgid "You are currently logued as an anonymous user."
msgstr ""
msgstr "Vous êtes actuellement connecté en tant qu'anonyme"
#: [room]anonymous_text2
msgid "You can join using your own account or create one on the login page by loging out using the cross in the top-right corner."
msgstr ""
msgstr "Vous pouvez vous connecter en utilisant votre propre compte ou en créer un sur la page de connexion, en cliquant sur la croix en haut à droite."
#: [room]anonymous_login
msgid "Login on %s"
msgstr ""
msgstr "Connexion sur %s"
#: [room]nick
msgid "Your nickname"
msgstr ""
msgstr "Votre surnom"
#: [roster]ungrouped
msgid "Ungrouped"
@ -1599,14 +1575,12 @@ msgid "Please enter a valid Jabber ID"
msgstr "Veuillez entrer un identifiant Jabber valide"
#: [roster]no_contacts_title
#, fuzzy
msgid "No contacts ?"
msgstr "Vos contacts"
msgstr ""
#: [roster]no_contacts_text
#, fuzzy
msgid "You can add one using the + button bellow"
msgstr "Pas de contacts? Vous pouvez en ajouter un en cliquant sur le bouton + ci-dessous ou aller sur la page Explorer"
msgstr ""
#: [roster]show_hide
msgid "Show/Hide"
@ -1689,9 +1663,8 @@ msgid "No contact specified"
msgstr "Aucun contact indiqué"
#: [upload]title
#, fuzzy
msgid "Upload a file"
msgstr "Téléverser"
msgstr ""
#: [upload]choose
msgid "Choose a file to upload"
@ -1718,10 +1691,9 @@ msgid "Your profile is now restricted"
msgstr "Votre profil est maintenant restreint"
#: [general]nickname
#, fuzzy
msgctxt "[general]nickname"
msgid "Nickname"
msgstr "Pseudonyme"
msgstr "Surnom"
#: [accounts]twitter
msgid "Twitter"
@ -1736,15 +1708,13 @@ msgid "Yahoo"
msgstr "Yahoo"
#: [accounts]accounts_nickname
#, fuzzy
msgctxt "[accounts]accounts_nickname"
msgid "Nickname"
msgstr "Pseudonyme"
msgstr "Surnom"
#: [accounts]accounts_yahoo
#, fuzzy
msgid "Yahoo Account"
msgstr "Compte"
msgstr "Compte Yahoo"
#: [privacy]privacy_title
msgid "Privacy Level"
@ -1880,7 +1850,7 @@ msgstr "Partager"
#: [page]room
msgid "Room"
msgstr ""
msgstr "Salon"
#: [error]error
msgid "Error: %s"
@ -2048,11 +2018,11 @@ msgstr "Connexion"
#: [button]bool_yes
msgid "Yes"
msgstr "Oui"
msgstr ""
#: [button]bool_no
msgid "No"
msgstr "Non"
msgstr ""
#: [button]return
msgid "Return"
@ -2111,10 +2081,9 @@ msgid "Sunday"
msgstr "Dimanche"
#: [gender]nil
#, fuzzy
msgctxt "[gender]nil"
msgid "None"
msgstr "Aucun"
msgstr ""
#: [gender]male
msgid "Male"
@ -2149,10 +2118,9 @@ msgid "Registered"
msgstr "Inscrit"
#: [marital]nil
#, fuzzy
msgctxt "[marital]nil"
msgid "None"
msgstr "Aucun"
msgstr ""
#: [marital]single
msgid "Single"
@ -2627,7 +2595,6 @@ msgid "Yesterday"
msgstr "Hier"
#: [date]ago
#, fuzzy
msgid "%d days ago"
msgstr " Il y a %d jours"
@ -2657,11 +2624,11 @@ msgstr "courriel"
#: [post]no_comments
msgid "No comments yet"
msgstr "Pas de commentaires pour le moment"
msgstr ""
#: [post]no_comments_stream
msgid "No comments stream"
msgstr "Pas de flux de commentaires"
msgstr ""
#: [post]no_load
msgid "Your feed cannot be loaded."
@ -2684,9 +2651,8 @@ msgid "Show the older comments"
msgstr "Afficher les commentaires plus anciens"
#: [post]comments_loading
#, fuzzy
msgid "Loading comments..."
msgstr "Chargement des commentaires…"
msgstr ""
#: [post]comments_get
msgid "Get the comments"
@ -2731,300 +2697,3 @@ msgstr "LAPI est indisponible pour le moment, réessayez plus tard."
#: [field]type_here
msgid "Type here"
msgstr "Rédigez votre message ici"
#~ msgid "Environment"
#~ msgstr "Environnement"
#~ msgid "You can login with Facebook (chat only) using %syour.id@chat.facebook.com%s and your password"
#~ msgstr "Vous pouvez vous connecter avec Facebook (messagerie instantanée uniquement) en entrant %svotre.id@chat.facebook.com%s et votre mot de passe"
#~ msgid "%sGmail accounts are also compatible%s but are not fully supported"
#~ msgstr "%sLes comptes Gmail sont aussi compatibles%s mais ne sont pas complètement pris en charge"
#~ msgid "You can login using your favorite Jabber account"
#~ msgstr "Vous pouvez vous connecter avec votre compte Jabber favori"
#~ msgid "or with our demonstration account"
#~ msgstr "ou avec notre compte de démonstration"
#~ msgid "%s has been removed from your public groups"
#~ msgstr "%s a été supprimé de vos groupes publics"
#~ msgid "Remove a chatroom"
#~ msgstr "Enlever un salon de discussion"
#~ msgid "You are going to remove the following chatroom. Please confirm your action."
#~ msgstr "Vous allez supprimer le salon de discussion suivant de vos signets. Confirmez sil vous plaît."
#~ msgid "Remote application incompatible"
#~ msgstr "Lapplication distante est incompatible"
#~ msgid "Remove"
#~ msgstr "Retirer"
#~ msgid "remorseful"
#~ msgstr "plein de remords"
#~ msgid "Movim's folder must be writable."
#~ msgstr "Le dossier racine de Movim doit être accessible en écriture."
#~ msgid "Couldn't create directory '%s'."
#~ msgstr "La création du répertoire '%s' est impossible."
#~ msgid "Couldn't create configuration file '%s'."
#~ msgstr "La création du fichier de configuration '%s' est impossible."
#~ msgid "Compatibility Test"
#~ msgstr "Test de compatibilité"
#~ msgid "User not logged in."
#~ msgstr "Vous n'êtes pas authentifié."
#~ msgid "JID not provided."
#~ msgstr "JID indisponible."
#~ msgid "jid '%s' is incorrect"
#~ msgstr "Le JID '%s' n'est pas valide"
#~ msgid "Cannot open log file '%s'"
#~ msgstr "Le journal '%s' ne peut être ouvert"
#~ msgid "%s - Account Creation"
#~ msgstr "%s - Création de compte"
#~ msgid "Remove this contact"
#~ msgstr "Supprimer ce contact"
#~ msgid "Debug console"
#~ msgstr "Console de débogage"
#~ msgid "Logout"
#~ msgstr "Se déconnecter"
#~ msgid "Decline"
#~ msgstr "Refuser"
#~ msgid "Loading the contact feed ..."
#~ msgstr "Chargement du flux ..."
#~ msgid "wants to talk with you"
#~ msgstr "veut discuter avec vous"
#~ msgid "or"
#~ msgstr "ou"
#~ msgid "Actual version : "
#~ msgstr "Version actuelle : "
#~ msgid "Install %s and %s packages"
#~ msgstr "Veuillez installer les paquets %s et %s"
#~ msgid "Update your PHP version or contact your server administrator"
#~ msgstr "Mettez à jour votre version de PHP ou contactez l'administrateur de votre serveur"
#~ msgid "Enable read and write rights on Movim's root folder"
#~ msgstr "Activez les droits de lecture et d'écriture sur le dossier racine de Movim"
#~ msgid "Please remove the %s folder in order to complete the installation"
#~ msgstr "Veuillez supprimer le dossier %s pour terminer l'installation"
#~ msgid "Database Movim schema installed"
#~ msgstr "Le schéma des tables a été installé"
#~ msgid "Valid Bosh"
#~ msgstr "Bosh valide"
#~ msgid "Success !"
#~ msgstr "Bravo !"
#~ msgid "The current BOSH URL in invalid"
#~ msgstr "L'URL Bosh donnée n'est pas valide"
#~ msgid "Loading your feed ..."
#~ msgstr "Chargement de votre flux ..."
#~ msgid "Show All"
#~ msgstr "Tout afficher"
#~ msgid "Follow"
#~ msgstr "Suivre"
#~ msgid "Database Detected"
#~ msgstr "Base de données détectée"
#~ msgid "Movim requires the %s extension."
#~ msgstr "Movim a besoin de l'extension %s."
#~ msgid "The following requirements were not met. Please make sure they are all satisfied in order to install Movim."
#~ msgstr "Les dépendances ci-dessous ne sont pas satisfaites. Assurez-vous qu'elles le soient afin d'installer Movim."
#~ msgid "You can now access your shiny Movim instance %sJump In !%s"
#~ msgstr "Vous pouvez maintenant accéder à votre version fraîchement installée de Movim %sAllons y !%s"
#~ msgid "Install the %s package"
#~ msgstr "Installer le paquet %s"
#~ msgid "XMPP Connection Preferences"
#~ msgstr "Configuration de la connexion XMPP"
#~ msgid "You entered different passwords"
#~ msgstr "Vous avez entré des mots de passe différents"
#~ msgid "BOSH Connection Preferences"
#~ msgstr "Configuration de la connexion BOSH"
#~ msgid "Wrong ID"
#~ msgstr "Mauvais identifiant"
#~ msgid "Only alphanumerics elements are authorized"
#~ msgstr "Seul des éléments alphanumériques sont autorisés"
#~ msgid "Make sure your password is safe :"
#~ msgstr "Soyez sur que votre mot de passe est suffisamment robuste :"
#~ msgid "Example :"
#~ msgstr "Exemple :"
#~ msgid "Same here !"
#~ msgstr "Même chôse ici !"
#~ msgid "Retype"
#~ msgstr "Retaper"
#~ msgid "Pseudo"
#~ msgstr "Pseudo"
#~ msgid "Create"
#~ msgstr "Créer"
#~ msgid "Create my vCard"
#~ msgstr "Créer ma vCard"
#~ msgid "A capital letter, a digit and a special character are recommended"
#~ msgstr "Un bon mot de passe est composé d'au moins une majuscule, un chiffre et un caractère spécial"
#~ msgid "8 characters"
#~ msgstr "8 caractères"
#~ msgid "Proxy Preferences"
#~ msgstr "Préférences du Proxy"
#~ msgid "Address"
#~ msgstr "Adresse"
#~ msgid "Firstly fill in this blank with a brand new account ID, this address will follow you on all the Movim network !"
#~ msgstr "Tout d'abord remplir ce vide avec un ID de tout nouveau compte, cette adresse vous suivra sur tout le réseau Movim !"
#~ msgid "%s - Add An Account"
#~ msgstr "%s - Ajouter Un Compte"
#~ msgid "Add your login informations"
#~ msgstr "Ajoutez vos informations de connexion"
#~ msgid "Client Name"
#~ msgstr "Nom du client"
#~ msgid "Client Type"
#~ msgstr "Type de Client"
#~ msgid "Contacts (%s)"
#~ msgstr "Contacts (%s)"
#~ msgid "Your server doesn't support post publication, you can only read contact's feeds"
#~ msgstr "Votre serveur ne gère pas la publication des billets, vous ne pouvez que lire les flux de vos contacts."
#~ msgid "No profile yet ?"
#~ msgstr "Pas encore de profil ?"
#~ msgid "Edit my Profile"
#~ msgstr "Modifier mon profil"
#~ msgid "PHP version mismatch. Movim requires PHP 5.3 minimum."
#~ msgstr "La version de PHP ne correspond pas. Movim nécessite la version 5.3 au minimum."
#~ msgid "normal"
#~ msgstr "standard"
#~ msgid "terse"
#~ msgstr "concis"
#~ msgid "empty"
#~ msgstr "vide"
#~ msgid "Keep in mind that Movim is still under development and will handle many personal details. Its use can potentially endanger your data. Always pay attention to information that you submit."
#~ msgstr "Gardez à l'esprit que Movim est encore en développement et va manipuler des informations personnelles. Son utilisation peut donc les mettre en danger. Faites donc toujours attention aux informations que vous envoyez."
#~ msgid "Before you enjoy your social network, a few adjustements are required."
#~ msgstr "Avant que vous utilisiez votre réseau social, quelques ajustements sont nécessaires."
#~ msgid "ultimate"
#~ msgstr "complet"
#~ msgid "talkative"
#~ msgstr "bavard"
#~ msgid "Although Movim is evolving fast, many (many) features are missing. Be patient ;). You can have a look %s at next versions's roadmaps %s to know if the one you want is on its way."
#~ msgstr "Même si Movim avance vite, il manque encore de (très) nombreuses fonctionnalités. Soyez patient ;). Vous pouvez aller jeter un œil aux %s feuilles de routes des prochaines version %s pour voir si celle-ci n'est pas déjà prévue."
#~ msgid "Go to the %s to the Frequently Asked Questions %s or come ask your question on the official chatroom %s or via our mailing-list (%s see the dedicated page %s)."
#~ msgstr "Allez jeter un oeil %s à la Foire aux Questions %s ou venez nous la poser directement sur le salon officiel %s ou sur la mailing-list (%s voir la page dédiée %s)."
#~ msgid "Don't forget that Movim is an open source project, a helping hand is always welcome (see %s Can I participate %s)"
#~ msgstr "Et n'oubliez pas que Movim est un logiciel libre, un petit coup de main est toujours le bienvenu (voir la page %s Puis-je participer %s)."
#~ msgid "Link my current account"
#~ msgstr "Lier mon compte actuel"
#~ msgid "Connecting..."
#~ msgstr "Connexion…"
#~ msgid "Invite this user"
#~ msgstr "Inviter cet utilisateur"
#~ msgid "Bosh connection failed with error '%s'"
#~ msgstr "La connection Bosh a échoué avec l'erreur '%s'"
#~ msgid "Database connection failed with error '%s'"
#~ msgstr "La connexion à la base de données à échoué avec l'erreur '%s'"
#~ msgid "XMPP connection through Bosh failed with error '%s'"
#~ msgstr "La connection XMPP à travers Bosh a échoué avec l'erreur '%s'"
#~ msgid "Send request"
#~ msgstr "Envoyer la demande"
#~ msgid "Thank you for downloading Movim!"
#~ msgstr "Merci d'avoir téléchargé Movim !"
#~ msgid "Some errors were detected. Please correct them for the installation to proceed."
#~ msgstr "Des erreurs ont été détectées. Veuillez les corriger pour terminer correctement l'installation."
#~ msgid "Cannot load element value '%s'"
#~ msgstr "Impossible de charger la valeur de l'élément « %s »"
#~ msgid "Invalid name"
#~ msgstr "Nom incorrect"
#~ msgid "Username already taken"
#~ msgstr "Identifiant déjà utilisé"
#~ msgid "What is Movim?"
#~ msgstr "Quest-ce que Movim?"
#~ msgid "My Posts"
#~ msgstr "Mes billets"
#~ msgid "I can't find the answer to my question here"
#~ msgstr "Ma question nest pas listée ici"
#~ msgid "Visit the page %s What is Movim ? %s to know more about the project, its aims and understand how it works."
#~ msgstr "Visitez la page %s Quest-ce que Movim ? %s pour en savoir plus le projet, ses buts et comprendre son fonctionnement."
#~ msgid "Some features are missing/I can't do everything I used to do on other social networks"
#~ msgstr "Il manque des fonctionnalités / Je narrive pas à faire ce que je faisais sur les autres réseaux sociaux"
#~ msgid "Could not communicate with the XMPP server"
#~ msgstr "Erreur de communication avec le serveur XMPP"
#~ msgid "Could not connect to the XMPP server"
#~ msgstr "Erreur de connexion au serveur XMPP"

View file

@ -0,0 +1,215 @@
<?php
namespace Movim\i18n;
class Locale {
private static $_instance;
public $translations;
public $language;
public $hash = array();
private function __construct()
{
$this->loadIni(
LOCALES_PATH . 'locales.ini',
true,
INI_SCANNER_RAW);
$dir = scandir(WIDGETS_PATH);
foreach($dir as $widget) {
$path = WIDGETS_PATH . $widget . '/locales.ini';
if(file_exists($path)) {
$this->loadIni($path);
}
}
}
/**
* @desc Load a locales ini file and merge it with hash attribute
* @param $file The path of the fie
*/
private function loadIni($file)
{
$this->hash = array_merge_recursive(
$this->hash,
parse_ini_file(
$file,
true,
INI_SCANNER_RAW
)
);
}
public static function start()
{
if(!isset(self::$_instance)) {
self::$_instance = new self();
}
return self::$_instance;
}
/**
* @desc Return an array containing all the presents languages in i18n
*/
public function getList() {
require_once('languages.php');
$lang_list = get_lang_list();
$dir = scandir(LOCALES_PATH);
$po = array();
foreach($dir as $files) {
$explode = explode('.', $files);
if(end($explode) == 'po') {
$po[$explode[0]] = $lang_list[$explode[0]];
}
}
return $po;
}
/**
* @desc Translate a key
* @param $key The key to translate
* @param $args Arguments to pass to sprintf
*/
public function translate($key, $args = false)
{
$arr = explode('.', $key);
if(is_array($this->hash)
&& array_key_exists($arr[0], $this->hash)
&& array_key_exists($arr[1], $this->hash[$arr[0]])) {
$skey = $this->hash[$arr[0]][$arr[1]];
if(is_array($this->translations)
&& array_key_exists($skey, $this->translations)
&& isset($this->translations[$skey])) {
$string = $this->translations[$skey];
} else {
if($this->language != 'en') {
\Utils::log('Locale: Translation not found in ['.$this->language.'] for "'.$key.'" : "'.$skey.'"');
}
if(is_string($skey)) {
$string = $skey;
} else {
\Utils::log('Locale: Double definition for "'.$key.'" got '.serialize($skey));
$string = $skey[0];
}
}
if($args != false) {
array_unshift($args, $string);
$string = call_user_func_array("sprintf", $args);
}
return $string;
} else {
\Utils::log('Locale: Translation key "'.$key.'" not found');
}
}
/**
* @desc Auto-detects the language from the user browser
*/
public function detect()
{
$langs = array();
preg_match_all(
'/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i',
$_SERVER['HTTP_ACCEPT_LANGUAGE'],
$lang_parse);
if (count($lang_parse[1])) {
$langs = array_combine($lang_parse[1], $lang_parse[4]);
foreach ($langs as $lang => $val) {
if ($val === '') $langs[$lang] = 1;
}
arsort($langs, SORT_NUMERIC);
}
while((list($key, $value) = each($langs))) {
if(file_exists(LOCALES_PATH . $key . '.po')) {
$this->language = $key;
return;
}
$exploded = explode('-', $key);
$key = reset($exploded);
if(file_exists(LOCALES_PATH . $key . '.po')) {
$this->language = $key;
return;
}
$this->language = 'en';
}
}
/**
* @desc Load a specific language
* @param $language The language key to load
*/
public function load($language)
{
$this->language = $language;
$this->loadPo();
}
/**
* @desc Parses a .po file based on the current language
*/
public function loadPo()
{
$pofile = LOCALES_PATH.$this->language.'.po';
if(!file_exists($pofile)) {
return false;
}
// Parsing the file.
$handle = fopen($pofile, 'r');
$this->translations = array();
$msgid = "";
$msgstr = "";
$last_token = "";
while($line = fgets($handle)) {
if($line[0] == "#" || trim(rtrim($line)) == "") {
continue;
}
if(preg_match('#^msgid#', $line)) {
if($last_token == "msgstr") {
$this->translations[$msgid] = $msgstr;
}
$last_token = "msgid";
$msgid = $this->getQuotedString($line);
}
else if(preg_match('#^msgstr#', $line)) {
$last_token = "msgstr";
$msgstr = $this->getQuotedString($line);
}
else {
$last_token .= $this->getQuotedString($line);
}
}
if($last_token == "msgstr") {
$this->translations[$msgid] = $msgstr;
}
fclose($handle);
}
private function getQuotedString($string)
{
$matches = array();
preg_match('#"(.+)"#', $string, $matches);
if(isset($matches[1]))
return $matches[1];
}
}

View file

@ -0,0 +1,206 @@
<?php
/**
* Return an array containing all the presents languages in i18n/
*
*/
function get_lang_list() {
$lang_list = array(
'aa' => "Afar",
'ab' => "Abkhazian",
'af' => "Afrikaans",
'am' => "Amharic",
'an' => "Aragon&#233;s",
'ar' => "&#1593;&#1585;&#1576;&#1610;",
'as' => "Assamese",
'ast' => "Asturianu",
'ay' => "Aymara",
'az' => "&#1040;&#1079;&#1241;&#1088;&#1073;&#1072;&#1112;&#1209;&#1072;&#1085;",
'ba' => "Bashkir",
'be' => "&#1041;&#1077;&#1083;&#1072;&#1088;&#1091;&#1089;&#1082;&#1110;",
'ber_tam' => "Tamazigh",
'ber_tam_tfng' => "Tamazigh tifinagh",
'bg' => "&#1073;&#1098;&#1083;&#1075;&#1072;&#1088;&#1089;&#1082;&#1080;",
'bh' => "Bihari",
'bi' => "Bislama",
'bm' => "Bambara",
'bn' => "Bengali; Bangla",
'bo' => "Tibetan",
'br' => "brezhoneg",
'bs' => "bosanski",
'ca' => "Catal&#224;",
'co' => "Corsu",
'cpf' => "Kr&eacute;ol r&eacute;yon&eacute;",
'cpf_dom' => "Krey&ograve;l",
'cpf_hat' => "Kr&eacute;y&ograve;l (P&eacute;yi Dayiti)",
'cs' => "&#269;e&#353;tina",
'cy' => "Cymraeg", # welsh, gallois
'da' => "Dansk",
'de' => "Deutsch",
'dz' => "Bhutani",
'el' => "&#949;&#955;&#955;&#951;&#957;&#953;&#954;&#940;",
'en' => "English",
'en_hx' => "H4ck3R",
'en_sm' => "Smurf",
'eo' => "Esperanto",
'es' => "Espa&#241;ol",
'es_co' => "Colombiano",
'et' => "Eesti",
'eu' => "Euskara",
'fa' => "&#1601;&#1575;&#1585;&#1587;&#1609;",
'ff' => "Fulah", // peul
'fi' => "Suomi",
'fj' => "Fiji",
'fo' => "F&#248;royskt",
'fon' => "Fongb&egrave;",
'fr' => "Fran&#231;ais",
'fr_sc' => "Schtroumpf",
'fr_lpc' => "Langue parl&#233;e compl&#233;t&#233;e",
'fr_lsf' => "Langue des signes fran&#231;aise",
'fr_spl' => "Fran&#231;ais simplifi&#233;",
'fr_tu' => "Fran&#231;ais copain",
'fy' => "Frisian",
'ga' => "Irish",
'gd' => "Scots Gaelic",
'gl' => "Galego",
'gn' => "Guarani",
'grc' => "&#7944;&#961;&#967;&#945;&#943;&#945; &#7961;&#955;&#955;&#951;&#957;&#953;&#954;&#942;", // grec ancien
'gu' => "Gujarati",
'ha' => "Hausa",
'hbo' => "&#1506;&#1489;&#1512;&#1497;&#1514;&#1470;&#1492;&#1514;&#1504;&#1498;", // hebreu classique ou biblique
'he' => "&#1506;&#1489;&#1512;&#1497;&#1514;",
'hi' => "&#2361;&#2367;&#2306;&#2342;&#2368;",
'hr' => "Hrvatski",
'hu' => "Magyar",
'hy' => "Armenian",
'ia' => "Interlingua",
'id' => "Indonesia",
'ie' => "Interlingue",
'io' => "Ido",
'ik' => "Inupiak",
'is' => "&#237;slenska",
'it' => "Italiano",
'it_fem' => "Italiana",
'iu' => "Inuktitut",
'ja' => "&#26085;&#26412;&#35486;",
'jv' => "Javanese",
'ka' => "&#4325;&#4304;&#4320;&#4311;&#4323;&#4314;&#4312;",
'kk' => "&#2325;&#2379;&#2306;&#2325;&#2339;&#2368;",
'kl' => "Kalaallisut",
'km' => "Cambodian",
'kn' => "Kannada",
'ko' => "&#54620;&#44397;&#50612;",
'ks' => "Kashmiri",
'ku' => "Kurdish",
'ky' => "Kirghiz",
'la' => "lingua latina",
'lb' => "L&euml;tzebuergesch",
'ln' => "Lingala",
'lo' => "&#3742;&#3762;&#3754;&#3762;&#3749;&#3762;&#3751;", # lao
'lt' => "Lietuvi&#371;",
'lu' => "Luba-katanga",
'lv' => "Latvie&#353;u",
'man' => "Mandingue", # a traduire en mandingue
'mfv' => "Manjak", # ISO-639-3
'mg' => "Malagasy",
'mi' => "Maori",
'mk' => "&#1084;&#1072;&#1082;&#1077;&#1076;&#1086;&#1085;&#1089;&#1082;&#1080; &#1112;&#1072;&#1079;&#1080;&#1082;",
'ml' => "Malayalam",
'mn' => "Mongolian",
'mo' => "Moldavian",
'mos' => "Mor&eacute;",
'mr' => "&#2350;&#2352;&#2366;&#2336;&#2368;",
'ms' => "Bahasa Malaysia",
'mt' => "Maltese",
'my' => "Burmese",
'na' => "Nauru",
'nap' => "Napulitano",
'ne' => "Nepali",
'nqo' => "N'ko", // www.manden.org
'nl' => "Nederlands",
'no' => "Norsk",
'nb' => "Norsk bokm&aring;l",
'nn' => "Norsk nynorsk",
'oc' => "&Ograve;c",
'oc_lnc' => "&Ograve;c lengadocian",
'oc_ni' => "&Ograve;c ni&ccedil;ard",
'oc_ni_la' => "&Ograve;c ni&ccedil;ard (larg)",
'oc_prv' => "&Ograve;c proven&ccedil;au",
'oc_gsc' => "&Ograve;c gascon",
'oc_lms' => "&Ograve;c lemosin",
'oc_auv' => "&Ograve;c auvernhat",
'oc_va' => "&Ograve;c vivaroaupenc",
'om' => "(Afan) Oromo",
'or' => "Oriya",
'pa' => "Punjabi",
'pbb' => 'Nasa Yuwe',
'pl' => "Polski",
'ps' => "Pashto, Pushto",
'pt' => "Portugu&#234;s",
'pt_br' => "Portugu&#234;s do Brasil",
'qu' => "Quechua",
'rm' => "Rhaeto-Romance",
'rn' => "Kirundi",
'ro' => "Rom&#226;n&#259;",
'roa' => "Ch'ti",
'ru' => "&#1088;&#1091;&#1089;&#1089;&#1082;&#1080;&#1081;",
'rw' => "Kinyarwanda",
'sa' => "&#2360;&#2306;&#2360;&#2381;&#2325;&#2371;&#2340;",
'sc' => "Sardu",
'scn' => "Sicilianu",
'sd' => "Sindhi",
'sg' => "Sangho",
'sh' => "Srpskohrvastski",
'sh_latn' => 'Srpskohrvastski',
'sh_cyrl' => '&#1057;&#1088;&#1087;&#1089;&#1082;&#1086;&#1093;&#1088;&#1074;&#1072;&#1090;&#1089;&#1082;&#1080;',
'si' => "Sinhalese",
'sk' => "Sloven&#269;ina", // (Slovakia)
'sl' => "Sloven&#353;&#269;ina", // (Slovenia)
'sm' => "Samoan",
'sn' => "Shona",
'so' => "Somali",
'sq' => "Shqip",
'sr' => "&#1089;&#1088;&#1087;&#1089;&#1082;&#1080;",
'src' => 'Sardu logudor&#233;su', // sarde cf 'sc'
'sro' => 'Sardu campidan&#233;su',
'ss' => "Siswati",
'st' => "Sesotho",
'su' => "Sundanese",
'sv' => "Svenska",
'sw' => "Kiswahili",
'ta' => "&#2980;&#2990;&#3007;&#2996;&#3021;", // Tamil
'te' => "Telugu",
'tg' => "Tajik",
'th' => "&#3652;&#3607;&#3618;",
'ti' => "Tigrinya",
'tk' => "Turkmen",
'tl' => "Tagalog",
'tn' => "Setswana",
'to' => "Tonga",
'tr' => "T&#252;rk&#231;e",
'ts' => "Tsonga",
'tt' => "&#1058;&#1072;&#1090;&#1072;&#1088;",
'tw' => "Twi",
'ty' => "Reo m&#257;`ohi", // tahitien
'ug' => "Uighur",
'uk' => "&#1091;&#1082;&#1088;&#1072;&#1111;&#1085;&#1089;&#1100;&#1082;&#1072;",
'ur' => "&#1649;&#1585;&#1583;&#1608;",
'uz' => "U'zbek",
'vi' => "Ti&#7871;ng Vi&#7879;t",
'vo' => "Volapuk",
'wa' => "Walon",
'wo' => "Wolof",
'xh' => "Xhosa",
'yi' => "Yiddish",
'yo' => "Yoruba",
'za' => "Zhuang",
'zh' => "&#20013;&#25991;", // chinois (ecriture simplifiee)
'zh_tw' => "&#21488;&#28771;&#20013;&#25991;", // chinois taiwan (ecr. traditionnelle)
'zu' => "Zulu"
);
return $lang_list;
}
?>

View file

@ -14,7 +14,7 @@ class Route extends \BaseController {
'conf' => false,
'contact' => array('f'),
'disconnect' => array('err'),
'feed' => array('f'),
'feed' => array('s', 'n'),
'grouppublic' => array('s', 'n', 'i'),
'group' => array('s', 'n', 'i'),
'help' => false,

View file

@ -53,7 +53,8 @@ class User {
$this->config = $session->config;
$lang = $this->getConfig('language');
if(isset($lang)) {
loadLanguage($lang);
$l = Movim\i18n\Locale::start();
$l->load($lang);
}
$cd = new modl\CapsDAO;

View file

@ -20,6 +20,25 @@ use Monolog\Logger;
use Monolog\Handler\SyslogHandler;
use Monolog\Handler\StreamHandler;
class Utils {
public static function log($message, $priority = '')
{
if(LOG_LEVEL != null && LOG_LEVEL > 0) {
$log = new Logger('movim');
$handler = new SyslogHandler('movim');
if(LOG_LEVEL > 1)
$log->pushHandler(new StreamHandler(LOG_PATH.'/movim.log', Logger::DEBUG));
$log->pushHandler($handler, Logger::DEBUG);
$errlines = explode("\n",$message);
foreach ($errlines as $txt) { $log->addDebug($txt); }
}
}
}
/**
* Return the list of gender
*/
@ -502,7 +521,6 @@ function generateUUID($string = false) {
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}
function movim_log($logs) {
$log = new Logger('movim');
$log->pushHandler(new SyslogHandler('movim'));
@ -614,4 +632,16 @@ function requestURL($url, $timeout = 10, $post = false) {
return false;
}
}
/*
* @desc Translate something
*/
function __() {
$args = func_get_args();
$l = Movim\i18n\Locale::start();
$string = array_shift($args);
return $l->translate($string, $args);
}
?>

View file

@ -0,0 +1,222 @@
<?php
class Locale {
private static $_instance;
public $translations;
public $language;
public $hash = array();
private function __construct()
{
$this->loadIni(
LOCALES_PATH . 'locales.ini',
true,
INI_SCANNER_RAW);
$dir = scandir(WIDGETS_PATH);
foreach($dir as $widget) {
$path = WIDGETS_PATH . $widget . '/locales.ini';
if(file_exists($path)) {
$this->loadIni($path);
}
}
}
/**
* @desc Load a locales ini file and merge it with hash attribute
* @param $file The path of the fie
*/
private function loadIni($file)
{
$this->hash = array_merge_recursive(
$this->hash,
parse_ini_file(
$file,
true,
INI_SCANNER_RAW
)
);
}
public static function start()
{
if(!isset(self::$_instance)) {
self::$_instance = new self();
}
return self::$_instance;
}
/**
* @desc Return an array containing all the presents languages in i18n
*/
public function getList() {
require_once('languages.php');
$lang_list = get_lang_list();
$dir = scandir(LOCALES_PATH);
$po = array();
foreach($dir as $files) {
$explode = explode('.', $files);
if(end($explode) == 'po') {
$po[$explode[0]] = $lang_list[$explode[0]];
}
}
return $po;
}
/**
* @desc Translate a key
* @param $key The key to translate
* @param $args Arguments to pass to sprintf
*/
public function translate($key, $args = false)
{
$arr = explode('.', $key);
if(is_array($this->hash)
&& array_key_exists($arr[0], $this->hash)
&& array_key_exists($arr[1], $this->hash[$arr[0]])) {
$skey = $this->hash[$arr[0]][$arr[1]];
if(is_array($this->translations)
&& array_key_exists($skey, $this->translations)
&& isset($this->translations[$skey])) {
$string = $this->translations[$skey];
} else {
if($this->language != 'en') {
Utils::log('Locale: Translation not found in ['.$this->language.'] for "'.$key.'" : "'.$skey.'"');
}
if(is_string($skey)) {
$string = $skey;
} else {
Utils::log('Locale: Double definition for "'.$key.'" got '.serialize($skey));
$string = $skey[0];
}
}
if($args != false) {
array_unshift($args, $string);
$string = call_user_func_array("sprintf", $args);
}
return $string;
} else {
Utils::log('Locale: Translation key "'.$key.'" not found');
}
}
/**
* @desc Auto-detects the language from the user browser
*/
public function detect()
{
$langs = array();
preg_match_all(
'/([a-z]{1,8}(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i',
$_SERVER['HTTP_ACCEPT_LANGUAGE'],
$lang_parse);
if (count($lang_parse[1])) {
$langs = array_combine($lang_parse[1], $lang_parse[4]);
foreach ($langs as $lang => $val) {
if ($val === '') $langs[$lang] = 1;
}
arsort($langs, SORT_NUMERIC);
}
while((list($key, $value) = each($langs))) {
if(file_exists(LOCALES_PATH . $key . '.po')) {
$this->language = $key;
return;
}
$exploded = explode('-', $key);
$key = reset($exploded);
if(file_exists(LOCALES_PATH . $key . '.po')) {
$this->language = $key;
return;
}
$this->language = 'en';
}
}
/**
* @desc Load a specific language
* @param $language The language key to load
*/
public function load($language)
{
$this->language = $language;
$this->loadPo();
}
/**
* @desc Parses a .po file based on the current language
*/
public function loadPo()
{
$pofile = LOCALES_PATH.$this->language.'.po';
if(!file_exists($pofile)) {
return false;
}
// Parsing the file.
$handle = fopen($pofile, 'r');
$this->translations = array();
$msgid = "";
$msgstr = "";
$last_token = "";
while($line = fgets($handle)) {
if($line[0] == "#" || trim(rtrim($line)) == "") {
continue;
}
if(preg_match('#^msgid#', $line)) {
if($last_token == "msgstr") {
$this->translations[$msgid] = $msgstr;
}
$last_token = "msgid";
$msgid = $this->getQuotedString($line);
}
else if(preg_match('#^msgstr#', $line)) {
$last_token = "msgstr";
$msgstr = $this->getQuotedString($line);
}
else {
$last_token .= $this->getQuotedString($line);
}
}
if($last_token == "msgstr") {
$this->translations[$msgid] = $msgstr;
}
fclose($handle);
}
private function getQuotedString($string)
{
$matches = array();
preg_match('#"(.+)"#', $string, $matches);
if(isset($matches[1]))
return $matches[1];
}
}
function __() {
$args = func_get_args();
$l = Locale::start();
$string = array_shift($args);
return $l->translate($string, $args);
}

View file

@ -27,7 +27,7 @@ class WidgetBase
protected $user;
protected $name;
protected $pure; // To render the widget without the container
protected $translations = array(); // Set translations in the controller
//protected $translations = array(); // Set translations in the controller
protected $_view;
public $events;
public $filters;
@ -73,11 +73,6 @@ class WidgetBase
'tpl_ext' => 'tpl',
'auto_escape' => false
);
if(file_exists($this->respath('locales.ini', true))) {
$this->translations = parse_ini_file($this->respath('locales.ini', true), true, INI_SCANNER_RAW);
}
// We load the template engine
$this->view = new Tpl;
$this->view->objectConfigure($config);
@ -87,30 +82,14 @@ class WidgetBase
$this->pure = false;
}
function __() {
function __()
{
$args = func_get_args();
global $translationshash;
if(!is_array($this->translations)) $this->translations = array();
$tmp_trans = array_merge_recursive($this->translations, $translationshash);
$arr = explode('.', $args[0]);
if(is_array($tmp_trans)
&& array_key_exists($arr[0], $tmp_trans)
&& array_key_exists($arr[1], $tmp_trans[$arr[0]])) {
$vars = $tmp_trans[$arr[0]][$arr[1]];
if(is_array($vars))
$args[0] = $vars[0];
else
$args[0] = $vars;
return call_user_func_array('t', $args);
} else {
return $args[0];
}
return call_user_func_array('__', $args);
}
function ___() {
function ___()
{
echo call_user_func_array(array(&$this, '__'), func_get_args());
}
@ -119,7 +98,8 @@ class WidgetBase
return $this->user->isSupported($key);
}
function route() {
function route()
{
return call_user_func_array('Route::urlize',func_get_args());
}
@ -147,9 +127,7 @@ class WidgetBase
function display() {}
/**
* Return the template's HTML code
* @param a specific template name to load (like Ruby partials)
* @param load the parent template, like for WidgetCommon
* àdesc Return the template's HTML code
*/
function draw()
{

View file

@ -89,7 +89,8 @@ article section content em {
/* Some CSS to style the quote XHTML generated by Movim */
article section content blockquote,
article section content q {
article section content q,
article section content div.quote {
display: block;
border-radius: 2px;
border: 1px solid rgba(0, 0, 0, 0.12);
@ -97,39 +98,45 @@ article section content q {
box-sizing: border-box;
}
article section content q:before,
article section content q:after {
article section content div.quote:before,
article section content div.quote:after {
content: '';
display: none;
}
article section content q ul {
article section content div.quote ul {
display: flex;
flex-flow: row wrap;
}
article section content q li {
article section content div.quote li {
flex: 1 25%;
list-style-type: none;
padding-left: 0;
}
article section content q li:first-child {
article section content div.quote li:first-child {
flex: 1 75%;
}
@media screen and (max-width: 1024px) {
article section content q li {
article section content div.quote li {
flex: 1 100%;
}
}
article section content q li img {
article section content div.quote li img {
max-height: 10rem;
max-width: 100%;
float: right;
}
article section content img.big_picture {
display: block;
margin: 0rem auto;
margin-bottom: 1rem;
}
article ul li.pic img {
max-width: 30rem;
max-height: 30rem;

View file

@ -218,6 +218,13 @@ form > div .radio > input[type="radio"]:checked + label:hover {
box-shadow: inset 0 0 0rem 0.4rem white, 0 0 0 1.5rem rgba(0, 0, 0, 0.1);
}
/* Disabled */
form > div > input:disabled,
form > div > input:disabled + label {
opacity: 0.5;
}
/* Button */
.button.oppose {

View file

@ -13,6 +13,7 @@ ul li {
}
ul > a {
max-width: 100%;
display: block;
}
@ -225,7 +226,7 @@ ul li div.bubble {
}
ul li div.bubble div {
white-space: pre-wrap;
/*white-space: pre-wrap;*/
display: inline;
}

View file

@ -152,12 +152,14 @@ body > nav.active {
width: 45rem;
}
@media screen and (min-width: 1024px) {
body > div.dialog:not(:empty) ~ main,
body > div.dialog:not(:empty) ~ nav,
body > nav.active + main {
opacity: 0.5;
pointer-events: none;
}
}
body > nav li { /* Little hack for the navbar */
overflow: hidden;
@ -227,6 +229,7 @@ main {
background-color: white;
-webkit-transition: opacity 0.3s ease-in-out;
transition: opacity 0.3s ease-in-out;
transform: translateZ(0);
}
nav + main {
@ -708,6 +711,20 @@ main section > div:first-child:nth-last-child(2) ~ div .actions.fixed > div:last
width: 40rem;
pointer-events: none;
transition: opacity 0.2s ease, bottom 0.4s ease;
transform: translateX(0);
}
.snackbar > a {
pointer-events: auto;
margin: -1rem -2rem;
display: block;
margin: -2rem -1rem;
padding: 2rem 1rem;
}
.snackbar > a:hover {
border: 3px solid rgba(255, 255, 255, 0.2);
padding: calc(2rem - 3px) calc(1rem - 3px);
}
.snackbar p,
@ -877,6 +894,7 @@ dl dd {
.spinner:before,
.spinner:after {
transition: top .3s ease-in-out;
transform: translateX(0);
content: '';
position: absolute;
left: calc(50% - 3.5rem);
@ -890,8 +908,8 @@ dl dd {
}
.spinner.on:before {
animation: spinner 1s linear infinite;
-webkit-animation: spinner 1s linear infinite;
animation: 1s spinner infinite linear;
-webkit-animation: 1s spinner 1s infinite linear;
}
.spinner:before {
@ -916,10 +934,12 @@ dl dd {
}
@keyframes spinner {
from { transform: rotate(0deg); }
to {transform: rotate(360deg);}
}
@-webkit-keyframes spinner {
from { transform: rotate(0deg); }
to {-webkit-transform: rotate(360deg);}
}