]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/MobileProfile/MobileProfilePlugin.php
Merge branch 'extprofile' into 0.9.x
[quix0rs-gnu-social.git] / plugins / MobileProfile / MobileProfilePlugin.php
1 <?php
2 /**
3  * StatusNet, the distributed open-source microblogging tool
4  *
5  * XHTML Mobile Profile plugin that uses WAP 2.0 Plugin
6  *
7  * PHP version 5
8  *
9  * LICENCE: This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU Affero General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Affero General Public License for more details.
18  *
19  * You should have received a copy of the GNU Affero General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  * @category  Plugin
23  * @package   StatusNet
24  * @author    Sarven Capadisli <csarven@status.net>
25  * @copyright 2009 StatusNet, Inc.
26  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
27  * @link      http://status.net/
28  */
29
30 if (!defined('STATUSNET') && !defined('LACONICA')) {
31     exit(1);
32 }
33
34 define('PAGE_TYPE_PREFS_MOBILEPROFILE',
35        'application/vnd.wap.xhtml+xml, application/xhtml+xml, text/html;q=0.9');
36
37 require_once INSTALLDIR.'/plugins/Mobile/WAP20Plugin.php';
38
39 /**
40  * Superclass for plugin to output XHTML Mobile Profile
41  *
42  * @category Plugin
43  * @package  StatusNet
44  * @author   Sarven Capadisli <csarven@status.net>
45  * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
46  * @link     http://status.net/
47  */
48 class MobileProfilePlugin extends WAP20Plugin
49 {
50     public $DTD            = null;
51     public $serveMobile    = false;
52     public $mobileFeatures = array();
53
54     function __construct($DTD='http://www.wapforum.org/DTD/xhtml-mobile10.dtd')
55     {
56         $this->DTD = $DTD;
57
58         parent::__construct();
59     }
60
61     function onStartShowHTML($action)
62     {
63         // XXX: This should probably graduate to WAP20Plugin
64
65         // If they are on the mobile site, serve them MP
66         if ((common_config('site', 'mobileserver').'/'.
67              common_config('site', 'path').'/' ==
68             $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'])) {
69
70             $this->serveMobile = true;
71         } else if (isset($_COOKIE['MobileOverride'])) {
72             // Cookie override is controlled by link at bottom.
73             $this->serveMobile = (bool)$_COOKIE['MobileOverride'];
74         } else {
75             // If they like the WAP 2.0 mimetype, serve them MP
76             // @fixme $type is undefined, making this if case useless and spewing errors.
77             // What's the intent?
78             //if (strstr('application/vnd.wap.xhtml+xml', $type) !== false) {
79             //    $this->serveMobile = true;
80             //} else {
81                 // If they are a mobile device that supports WAP 2.0,
82                 // serve them MP
83
84                 // XXX: Browser sniffing sucks
85
86                 // I really don't like going through this every page,
87                 // perhaps use $_SESSION or cookies
88
89                 // May be better to group the devices in terms of
90                 // low,mid,high-end
91
92                 // Or, detect the mobile devices based on their support for
93                 // MP 1.0, 1.1, or 1.2 may be ideal. Possible?
94
95                 $this->mobiledevices = array(
96                     'alcatel',
97                     'android',
98                     'audiovox',
99                     'au-mic,',
100                     'avantgo',
101                     'blackberry',
102                     'blazer',
103                     'cldc-',
104                     'danger',
105                     'epoc',
106                     'ericsson',
107                     'ericy',
108                     'iphone',
109                     'ipaq',
110                     'ipod',
111                     'j2me',
112                     'lg',
113                     'midp-',
114                     'mobile',
115                     'mot',
116                     'netfront',
117                     'nitro',
118                     'nokia',
119                     'opera mini',
120                     'palm',
121                     'palmsource',
122                     'panasonic',
123                     'philips',
124                     'pocketpc',
125                     'portalmmm',
126                     'rover',
127                     'samsung',
128                     'sanyo',
129                     'series60',
130                     'sharp',
131                     'sie-',
132                     'smartphone',
133                     'sony',
134                     'symbian',
135                     'up.browser',
136                     'up.link',
137                     'up.link',
138                     'vodafone',
139                     'wap1',
140                     'wap2',
141                     'webos',
142                     'windows ce'
143                 );
144
145                 $blacklist = array(
146                     'ipad', // Larger screen handles the full theme fairly well.
147                 );
148
149                 $httpuseragent = strtolower($_SERVER['HTTP_USER_AGENT']);
150
151                 foreach ($blacklist as $md) {
152                     if (strstr($httpuseragent, $md) !== false) {
153                         $this->serveMobile = false;
154                         return true;
155                     }
156                 }
157
158                 foreach ($this->mobiledevices as $md) {
159                     if (strstr($httpuseragent, $md) !== false) {
160                         $this->setMobileFeatures($httpuseragent);
161
162                         $this->serveMobile = true;
163                         break;
164                     }
165                 }
166             //}
167
168             // If they are okay with MP, and the site has a mobile server,
169             // redirect there
170             if ($this->serveMobile &&
171                 common_config('site', 'mobileserver') !== false &&
172                 (common_config('site', 'mobileserver') !=
173                     common_config('site', 'server'))) {
174
175                 // FIXME: Redirect to equivalent page on mobile site instead
176                 common_redirect($this->_common_path(''), 302);
177             }
178         }
179
180         if (!$this->serveMobile) {
181             return true;
182         }
183
184         // @fixme $type is undefined, making this if case useless and spewing errors.
185         // What's the intent?
186         //if (!$type) {
187             $httpaccept = isset($_SERVER['HTTP_ACCEPT']) ?
188               $_SERVER['HTTP_ACCEPT'] : null;
189
190             $cp = common_accept_to_prefs($httpaccept);
191             $sp = common_accept_to_prefs(PAGE_TYPE_PREFS_MOBILEPROFILE);
192
193             $type = common_negotiate_type($cp, $sp);
194
195             if (!$type) {
196                 throw new ClientException(_m('This page is not available in a '.
197                                             'media type you accept.'), 406);
198             }
199         //}
200
201         header('Content-Type: '.$type);
202
203         $action->extraHeaders();
204         if (preg_match("/.*\/.*xml/", $type)) {
205             // Required for XML documents
206             $action->xw->startDocument('1.0', 'UTF-8');
207         }
208         $action->xw->writeDTD('html',
209                         '-//WAPFORUM//DTD XHTML Mobile 1.0//EN',
210                         $this->DTD);
211
212         $language = $action->getLanguage();
213
214         $action->elementStart('html', array('xmlns' => 'http://www.w3.org/1999/xhtml',
215                                             'xml:lang' => $language));
216
217         return false;
218     }
219
220     function setMobileFeatures($useragent)
221     {
222         $mobiledeviceInputFileType = array(
223             'nokia'
224         );
225
226         $this->mobileFeatures['inputfiletype'] = false;
227
228         foreach ($mobiledeviceInputFileType as $md) {
229             if (strstr($useragent, $md) !== false) {
230                 $this->mobileFeatures['inputfiletype'] = true;
231                 break;
232             }
233         }
234     }
235
236     function onStartShowStatusNetStyles($action)
237     {
238         if (!$this->serveMobile) {
239             return true;
240         }
241
242         $action->primaryCssLink();
243
244         if (file_exists(Theme::file('css/mp-screen.css'))) {
245             $action->cssLink('css/mp-screen.css', null, 'screen');
246         } else {
247             $action->cssLink($this->path('mp-screen.css'),null,'screen');
248         }
249
250         if (file_exists(Theme::file('css/mp-handheld.css'))) {
251             $action->cssLink('css/mp-handheld.css', null, 'handheld');
252         } else {
253             $action->cssLink($this->path('mp-handheld.css'),null,'handheld');
254         }
255
256         // Allow other plugins to load their styles.
257         Event::handle('EndShowStatusNetStyles', array($action));
258         Event::handle('EndShowLaconicaStyles', array($action));
259
260         return false;
261     }
262
263     function onStartShowUAStyles($action) {
264         if (!$this->serveMobile) {
265             return true;
266         }
267
268         return false;
269     }
270
271     function onStartShowHeader($action)
272     {
273         if (!$this->serveMobile) {
274             return true;
275         }
276
277         $action->elementStart('div', array('id' => 'header'));
278         $this->_showLogo($action);
279         $this->_showPrimaryNav($action);
280         if (common_logged_in()) {
281             $action->showNoticeForm();
282         }
283         $action->elementEnd('div');
284
285         return false;
286     }
287
288     function _showLogo($action)
289     {
290         $action->elementStart('address', 'vcard');
291         $action->elementStart('a', array('class' => 'url home bookmark',
292                                        'href' => common_local_url('public')));
293         if (common_config('site', 'mobilelogo') ||
294             file_exists(Theme::file('logo.png')) ||
295             file_exists(Theme::file('mobilelogo.png'))) {
296
297             $action->element('img', array('class' => 'photo',
298                 'src' => (common_config('site', 'mobilelogo')) ? common_config('site', 'mobilelogo') :
299                             ((file_exists(Theme::file('mobilelogo.png'))) ? (Theme::path('mobilelogo.png')) : Theme::path('logo.png')),
300                 'alt' => common_config('site', 'name')));
301         }
302         $action->element('span', array('class' => 'fn org'), common_config('site', 'name'));
303         $action->elementEnd('a');
304         $action->elementEnd('address');
305     }
306
307     function _showPrimaryNav($action)
308     {
309         $user    = common_current_user();
310         $action->elementStart('ul', array('id' => 'site_nav_global_primary'));
311         if ($user) {
312             $action->menuItem(common_local_url('all', array('nickname' => $user->nickname)),
313                             _m('Home'));
314             $action->menuItem(common_local_url('profilesettings'),
315                             _m('Account'));
316             $action->menuItem(common_local_url('oauthconnectionssettings'),
317                                 _m('Connect'));
318             if ($user->hasRight(Right::CONFIGURESITE)) {
319                 $action->menuItem(common_local_url('siteadminpanel'),
320                                 _m('Admin'), _m('Change site configuration'), false, 'nav_admin');
321             }
322             if (common_config('invite', 'enabled')) {
323                 $action->menuItem(common_local_url('invite'),
324                                 _m('Invite'));
325             }
326             $action->menuItem(common_local_url('logout'),
327                             _m('Logout'));
328         } else {
329             if (!common_config('site', 'closed')) {
330                 $action->menuItem(common_local_url('register'),
331                                 _m('Register'));
332             }
333             $action->menuItem(common_local_url('login'),
334                             _m('Login'));
335         }
336         if ($user || !common_config('site', 'private')) {
337             $action->menuItem(common_local_url('peoplesearch'),
338                             _m('Search'));
339         }
340         $action->elementEnd('ul');
341     }
342
343     function onStartShowNoticeFormData($form)
344     {
345         if (!$this->serveMobile) {
346             return true;
347         }
348
349         $form->out->element('textarea', array('id' => 'notice_data-text',
350                                               'cols' => 15,
351                                               'rows' => 4,
352                                               'name' => 'status_textarea'),
353                             ($form->content) ? $form->content : '');
354
355         $contentLimit = Notice::maxContent();
356
357         if ($contentLimit > 0) {
358             $form->out->element('div', array('id' => 'notice_text-count'),
359                                 $contentLimit);
360         }
361
362         if (common_config('attachments', 'uploads')) {
363             if ($this->mobileFeatures['inputfiletype']) {
364                 $form->out->hidden('MAX_FILE_SIZE', common_config('attachments', 'file_quota'));
365                 $form->out->element('label', array('for' => 'notice_data-attach'), _m('Attach'));
366                 $form->out->element('input', array('id' => 'notice_data-attach',
367                                                    'type' => 'file',
368                                                    'name' => 'attach',
369                                                    'title' => _m('Attach a file')));
370             }
371         }
372         if ($form->action) {
373             $form->out->hidden('notice_return-to', $form->action, 'returnto');
374         }
375         $form->out->hidden('notice_in-reply-to', $form->inreplyto, 'inreplyto');
376
377         return false;
378     }
379
380     function onStartShowAside($action)
381     {
382         if ($this->serveMobile) {
383             return false;
384         }
385     }
386
387     function onEndShowScripts($action)
388     {
389         $action->inlineScript('
390             $(function() {
391                 $("#mobile-toggle-disable").click(function() {
392                     $.cookie("MobileOverride", "0", {path: "/"});
393                     window.location.reload();
394                     return false;
395                 });
396                 $("#mobile-toggle-enable").click(function() {
397                     $.cookie("MobileOverride", "1", {path: "/"});
398                     window.location.reload();
399                     return false;
400                 });
401             });'
402         );
403     }
404
405
406     function onEndShowInsideFooter($action)
407     {
408         if ($this->serveMobile) {
409             // TRANS: Link to switch site layout from mobile to desktop mode. Appears at very bottom of page.
410             $linkText = _m('Switch to desktop site layout.');
411             $key = 'mobile-toggle-disable';
412         } else {
413             // TRANS: Link to switch site layout from desktop to mobile mode. Appears at very bottom of page.
414             $linkText = _m('Switch to mobile site layout.');
415             $key = 'mobile-toggle-enable';
416         }
417         $action->elementStart('p');
418         $action->element('a', array('href' => '#', 'id' => $key), $linkText);
419         $action->elementEnd('p');
420         return true;
421     }
422
423     function _common_path($relative, $ssl=false)
424     {
425         $pathpart = (common_config('site', 'path')) ? common_config('site', 'path')."/" : '';
426
427         if (($ssl && (common_config('site', 'ssl') === 'sometimes'))
428             || common_config('site', 'ssl') === 'always') {
429             $proto = 'https';
430             if (is_string(common_config('site', 'sslserver')) &&
431                 mb_strlen(common_config('site', 'sslserver')) > 0) {
432                 $serverpart = common_config('site', 'sslserver');
433             } else {
434                 $serverpart = common_config('site', 'mobileserver');
435             }
436         } else {
437             $proto      = 'http';
438             $serverpart = common_config('site', 'mobileserver');
439         }
440
441         return $proto.'://'.$serverpart.'/'.$pathpart.$relative;
442     }
443
444     function onPluginVersion(&$versions)
445     {
446         $versions[] = array('name' => 'MobileProfile',
447                             'version' => STATUSNET_VERSION,
448                             'author' => 'Sarven Capadisli',
449                             'homepage' => 'http://status.net/wiki/Plugin:MobileProfile',
450                             'rawdescription' =>
451                             _m('XHTML MobileProfile output for supporting user agents.'));
452         return true;
453     }
454 }