]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/MobileProfile/MobileProfilePlugin.php
Ticket #2184: recognize Palm Pre / WebOS browsers for MobileProfile
[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->cssLink('css/display.css');
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         return false;
259     }
260
261
262     function onStartShowUAStyles($action) {
263         if (!$this->serveMobile) {
264             return true;
265         }
266
267         return false;
268     }
269
270     function onStartShowHeader($action)
271     {
272         if (!$this->serveMobile) {
273             return true;
274         }
275
276         $action->elementStart('div', array('id' => 'header'));
277         $this->_showLogo($action);
278         $this->_showPrimaryNav($action);
279         if (common_logged_in()) {
280             $action->showNoticeForm();
281         }
282         $action->elementEnd('div');
283
284         return false;
285     }
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
308     function _showPrimaryNav($action)
309     {
310         $user    = common_current_user();
311         $action->elementStart('ul', array('id' => 'site_nav_global_primary'));
312         if ($user) {
313             $action->menuItem(common_local_url('all', array('nickname' => $user->nickname)),
314                             _('Home'));
315             $action->menuItem(common_local_url('profilesettings'),
316                             _('Account'));
317             $action->menuItem(common_local_url('oauthconnectionssettings'),
318                                 _('Connect'));
319             if ($user->hasRight(Right::CONFIGURESITE)) {
320                 $action->menuItem(common_local_url('siteadminpanel'),
321                                 _('Admin'), _('Change site configuration'), false, 'nav_admin');
322             }
323             if (common_config('invite', 'enabled')) {
324                 $action->menuItem(common_local_url('invite'),
325                                 _('Invite'));
326             }
327             $action->menuItem(common_local_url('logout'),
328                             _('Logout'));
329         } else {
330             if (!common_config('site', 'closed')) {
331                 $action->menuItem(common_local_url('register'),
332                                 _('Register'));
333             }
334             $action->menuItem(common_local_url('login'),
335                             _('Login'));
336         }
337         if ($user || !common_config('site', 'private')) {
338             $action->menuItem(common_local_url('peoplesearch'),
339                             _('Search'));
340         }
341         $action->elementEnd('ul');
342     }
343
344
345     function onStartShowNoticeFormData($form)
346     {
347         if (!$this->serveMobile) {
348             return true;
349         }
350
351         $form->out->element('textarea', array('id' => 'notice_data-text',
352                                               'cols' => 15,
353                                               'rows' => 4,
354                                               'name' => 'status_textarea'),
355                             ($form->content) ? $form->content : '');
356
357         $contentLimit = Notice::maxContent();
358
359         if ($contentLimit > 0) {
360             $form->out->element('div', array('id' => 'notice_text-count'),
361                                 $contentLimit);
362         }
363
364         if (common_config('attachments', 'uploads')) {
365             if ($this->mobileFeatures['inputfiletype']) {
366                 $form->out->element('label', array('for' => 'notice_data-attach'), _('Attach'));
367                 $form->out->element('input', array('id' => 'notice_data-attach',
368                                                    'type' => 'file',
369                                                    'name' => 'attach',
370                                                    'title' => _('Attach a file')));
371                 $form->out->hidden('MAX_FILE_SIZE', common_config('attachments', 'file_quota'));
372             }
373         }
374         if ($form->action) {
375             $form->out->hidden('notice_return-to', $form->action, 'returnto');
376         }
377         $form->out->hidden('notice_in-reply-to', $form->inreplyto, 'inreplyto');
378
379         return false;
380     }
381
382
383     function onStartShowAside($action)
384     {
385         if ($this->serveMobile) {
386             return false;
387         }
388     }
389
390
391     function onStartShowScripts($action)
392     {
393
394     }
395
396
397     function _common_path($relative, $ssl=false)
398     {
399         $pathpart = (common_config('site', 'path')) ? common_config('site', 'path')."/" : '';
400
401         if (($ssl && (common_config('site', 'ssl') === 'sometimes'))
402             || common_config('site', 'ssl') === 'always') {
403             $proto = 'https';
404             if (is_string(common_config('site', 'sslserver')) &&
405                 mb_strlen(common_config('site', 'sslserver')) > 0) {
406                 $serverpart = common_config('site', 'sslserver');
407             } else {
408                 $serverpart = common_config('site', 'mobileserver');
409             }
410         } else {
411             $proto      = 'http';
412             $serverpart = common_config('site', 'mobileserver');
413         }
414
415         return $proto.'://'.$serverpart.'/'.$pathpart.$relative;
416     }
417
418     function onPluginVersion(&$versions)
419     {
420         $versions[] = array('name' => 'MobileProfile',
421                             'version' => STATUSNET_VERSION,
422                             'author' => 'Sarven Capadisli',
423                             'homepage' => 'http://status.net/wiki/Plugin:MobileProfile',
424                             'rawdescription' =>
425                             _m('XHTML MobileProfile output for supporting user agents.'));
426         return true;
427     }
428 }