]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/MobileProfile/MobileProfilePlugin.php
Fix for ticket 2756 - Calls to OAuth endpoints are redirected to the
[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 /**
41  * Superclass for plugin to output XHTML Mobile Profile
42  *
43  * @category Plugin
44  * @package  StatusNet
45  * @author   Sarven Capadisli <csarven@status.net>
46  * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
47  * @link     http://status.net/
48  */
49
50 class MobileProfilePlugin extends WAP20Plugin
51 {
52     public $DTD            = null;
53     public $serveMobile    = false;
54     public $mobileFeatures = array();
55
56     function __construct($DTD='http://www.wapforum.org/DTD/xhtml-mobile10.dtd')
57     {
58         $this->DTD = $DTD;
59
60         parent::__construct();
61     }
62
63
64     function onStartShowHTML($action)
65     {
66         // XXX: This should probably graduate to WAP20Plugin
67
68         // If they are on the mobile site, serve them MP
69         if ((common_config('site', 'mobileserver').'/'.
70              common_config('site', 'path').'/' == 
71             $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'])) {
72
73             $this->serveMobile = true;
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(_('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
221     function setMobileFeatures($useragent)
222     {
223         $mobiledeviceInputFileType = array(
224             'nokia'
225         );
226
227         $this->mobileFeatures['inputfiletype'] = false;
228
229         foreach ($mobiledeviceInputFileType as $md) {
230             if (strstr($useragent, $md) !== false) {
231                 $this->mobileFeatures['inputfiletype'] = true;
232                 break;
233             }
234         }
235     }
236
237
238     function onStartShowStatusNetStyles($action)
239     {
240         if (!$this->serveMobile) {
241             return true;
242         }
243
244         $action->primaryCssLink();
245
246         if (file_exists(Theme::file('css/mp-screen.css'))) {
247             $action->cssLink('css/mp-screen.css', null, 'screen');
248         } else {
249             $action->cssLink('plugins/MobileProfile/mp-screen.css',null,'screen');
250         }
251
252         if (file_exists(Theme::file('css/mp-handheld.css'))) {
253             $action->cssLink('css/mp-handheld.css', null, 'handheld');
254         } else {
255             $action->cssLink('plugins/MobileProfile/mp-handheld.css',null,'handheld');
256         }
257
258         // Allow other plugins to load their styles.
259         Event::handle('EndShowStatusNetStyles', array($action));
260         Event::handle('EndShowLaconicaStyles', array($action));
261
262         return false;
263     }
264
265
266     function onStartShowUAStyles($action) {
267         if (!$this->serveMobile) {
268             return true;
269         }
270
271         return false;
272     }
273
274     function onStartShowHeader($action)
275     {
276         if (!$this->serveMobile) {
277             return true;
278         }
279
280         $action->elementStart('div', array('id' => 'header'));
281         $this->_showLogo($action);
282         $this->_showPrimaryNav($action);
283         if (common_logged_in()) {
284             $action->showNoticeForm();
285         }
286         $action->elementEnd('div');
287
288         return false;
289     }
290
291
292     function _showLogo($action)
293     {
294         $action->elementStart('address', 'vcard');
295         $action->elementStart('a', array('class' => 'url home bookmark',
296                                        'href' => common_local_url('public')));
297         if (common_config('site', 'mobilelogo') || 
298             file_exists(Theme::file('logo.png')) || 
299             file_exists(Theme::file('mobilelogo.png'))) {
300
301             $action->element('img', array('class' => 'photo',
302                 'src' => (common_config('site', 'mobilelogo')) ? common_config('site', 'mobilelogo') : 
303                             ((file_exists(Theme::file('mobilelogo.png'))) ? (Theme::path('mobilelogo.png')) : Theme::path('logo.png')),
304                 'alt' => common_config('site', 'name')));
305         }
306         $action->element('span', array('class' => 'fn org'), common_config('site', 'name'));
307         $action->elementEnd('a');
308         $action->elementEnd('address');
309     }
310
311
312     function _showPrimaryNav($action)
313     {
314         $user    = common_current_user();
315         $action->elementStart('ul', array('id' => 'site_nav_global_primary'));
316         if ($user) {
317             $action->menuItem(common_local_url('all', array('nickname' => $user->nickname)),
318                             _('Home'));
319             $action->menuItem(common_local_url('profilesettings'),
320                             _('Account'));
321             $action->menuItem(common_local_url('oauthconnectionssettings'),
322                                 _('Connect'));
323             if ($user->hasRight(Right::CONFIGURESITE)) {
324                 $action->menuItem(common_local_url('siteadminpanel'),
325                                 _('Admin'), _('Change site configuration'), false, 'nav_admin');
326             }
327             if (common_config('invite', 'enabled')) {
328                 $action->menuItem(common_local_url('invite'),
329                                 _('Invite'));
330             }
331             $action->menuItem(common_local_url('logout'),
332                             _('Logout'));
333         } else {
334             if (!common_config('site', 'closed')) {
335                 $action->menuItem(common_local_url('register'),
336                                 _('Register'));
337             }
338             $action->menuItem(common_local_url('login'),
339                             _('Login'));
340         }
341         if ($user || !common_config('site', 'private')) {
342             $action->menuItem(common_local_url('peoplesearch'),
343                             _('Search'));
344         }
345         $action->elementEnd('ul');
346     }
347
348
349     function onStartShowNoticeFormData($form)
350     {
351         if (!$this->serveMobile) {
352             return true;
353         }
354
355         $form->out->element('textarea', array('id' => 'notice_data-text',
356                                               'cols' => 15,
357                                               'rows' => 4,
358                                               'name' => 'status_textarea'),
359                             ($form->content) ? $form->content : '');
360
361         $contentLimit = Notice::maxContent();
362
363         if ($contentLimit > 0) {
364             $form->out->element('div', array('id' => 'notice_text-count'),
365                                 $contentLimit);
366         }
367
368         if (common_config('attachments', 'uploads')) {
369             if ($this->mobileFeatures['inputfiletype']) {
370                 $form->out->element('label', array('for' => 'notice_data-attach'), _('Attach'));
371                 $form->out->element('input', array('id' => 'notice_data-attach',
372                                                    'type' => 'file',
373                                                    'name' => 'attach',
374                                                    'title' => _('Attach a file')));
375                 $form->out->hidden('MAX_FILE_SIZE', common_config('attachments', 'file_quota'));
376             }
377         }
378         if ($form->action) {
379             $form->out->hidden('notice_return-to', $form->action, 'returnto');
380         }
381         $form->out->hidden('notice_in-reply-to', $form->inreplyto, 'inreplyto');
382
383         return false;
384     }
385
386
387     function onStartShowAside($action)
388     {
389         if ($this->serveMobile) {
390             return false;
391         }
392     }
393
394
395     function onStartShowScripts($action)
396     {
397
398     }
399
400
401     function _common_path($relative, $ssl=false)
402     {
403         $pathpart = (common_config('site', 'path')) ? common_config('site', 'path')."/" : '';
404
405         if (($ssl && (common_config('site', 'ssl') === 'sometimes'))
406             || common_config('site', 'ssl') === 'always') {
407             $proto = 'https';
408             if (is_string(common_config('site', 'sslserver')) &&
409                 mb_strlen(common_config('site', 'sslserver')) > 0) {
410                 $serverpart = common_config('site', 'sslserver');
411             } else {
412                 $serverpart = common_config('site', 'mobileserver');
413             }
414         } else {
415             $proto      = 'http';
416             $serverpart = common_config('site', 'mobileserver');
417         }
418
419         return $proto.'://'.$serverpart.'/'.$pathpart.$relative;
420     }
421
422     function onPluginVersion(&$versions)
423     {
424         $versions[] = array('name' => 'MobileProfile',
425                             'version' => STATUSNET_VERSION,
426                             'author' => 'Sarven Capadisli',
427                             'homepage' => 'http://status.net/wiki/Plugin:MobileProfile',
428                             'rawdescription' =>
429                             _m('XHTML MobileProfile output for supporting user agents.'));
430         return true;
431     }
432 }