]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/MobileProfile/MobileProfilePlugin.php
Merge commit 'refs/merge-requests/166' of git://gitorious.org/statusnet/mainline...
[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 $reallyMobile   = false;
53     public $mobileFeatures = array();
54
55     function __construct($DTD='http://www.wapforum.org/DTD/xhtml-mobile10.dtd')
56     {
57         $this->DTD = $DTD;
58
59         parent::__construct();
60     }
61
62     function onStartShowHTML($action)
63     {
64         // XXX: This should probably graduate to WAP20Plugin
65
66         // If they are on the mobile site, serve them MP
67         if ((common_config('site', 'mobileserver').'/'.
68              common_config('site', 'path').'/' ==
69             $_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'])) {
70
71             $this->serveMobile = true;
72         } else if (isset($_COOKIE['MobileOverride'])) {
73             // Cookie override is controlled by link at bottom.
74             $this->serveMobile = (bool)$_COOKIE['MobileOverride'];
75         } else {
76             // If they like the WAP 2.0 mimetype, serve them MP
77             // @fixme $type is undefined, making this if case useless and spewing errors.
78             // What's the intent?
79             //if (strstr('application/vnd.wap.xhtml+xml', $type) !== false) {
80             //    $this->serveMobile = true;
81             //} else {
82                 // If they are a mobile device that supports WAP 2.0,
83                 // serve them MP
84
85                 // XXX: Browser sniffing sucks
86
87                 // I really don't like going through this every page,
88                 // perhaps use $_SESSION or cookies
89
90                 // May be better to group the devices in terms of
91                 // low,mid,high-end
92
93                 // Or, detect the mobile devices based on their support for
94                 // MP 1.0, 1.1, or 1.2 may be ideal. Possible?
95
96                 $this->mobiledevices = array(
97                     'alcatel',
98                     'android',
99                     'audiovox',
100                     'au-mic,',
101                     'avantgo',
102                     'blackberry',
103                     'blazer',
104                     'cldc-',
105                     'danger',
106                     'epoc',
107                     'ericsson',
108                     'ericy',
109                     'iphone',
110                     'ipaq',
111                     'ipod',
112                     'j2me',
113                     'lg',
114                     'midp-',
115                     'mobile',
116                     'mot',
117                     'netfront',
118                     'nitro',
119                     'nokia',
120                     'opera mini',
121                     'palm',
122                     'palmsource',
123                     'panasonic',
124                     'philips',
125                     'pocketpc',
126                     'portalmmm',
127                     'rover',
128                     'samsung',
129                     'sanyo',
130                     'series60',
131                     'sharp',
132                     'sie-',
133                     'smartphone',
134                     'sony',
135                     'symbian',
136                     'up.browser',
137                     'up.link',
138                     'up.link',
139                     'vodafone',
140                     'wap1',
141                     'wap2',
142                     'webos',
143                     'windows ce'
144                 );
145
146                 $blacklist = array(
147                     'ipad', // Larger screen handles the full theme fairly well.
148                 );
149
150                 $httpuseragent = strtolower($_SERVER['HTTP_USER_AGENT']);
151
152                 foreach ($blacklist as $md) {
153                     if (strstr($httpuseragent, $md) !== false) {
154                         $this->serveMobile = false;
155                         return true;
156                     }
157                 }
158
159                 foreach ($this->mobiledevices as $md) {
160                     if (strstr($httpuseragent, $md) !== false) {
161                         $this->setMobileFeatures($httpuseragent);
162
163                         $this->serveMobile = true;
164                         $this->reallyMobile = true;
165                         break;
166                     }
167                 }
168             //}
169
170             // If they are okay with MP, and the site has a mobile server,
171             // redirect there
172             if ($this->serveMobile &&
173                 common_config('site', 'mobileserver') !== false &&
174                 (common_config('site', 'mobileserver') !=
175                     common_config('site', 'server'))) {
176
177                 // FIXME: Redirect to equivalent page on mobile site instead
178                 common_redirect($this->_common_path(''), 302);
179             }
180         }
181
182         if (!$this->serveMobile) {
183             return true;
184         }
185
186         // @fixme $type is undefined, making this if case useless and spewing errors.
187         // What's the intent?
188         //if (!$type) {
189             $httpaccept = isset($_SERVER['HTTP_ACCEPT']) ?
190               $_SERVER['HTTP_ACCEPT'] : null;
191
192             $cp = common_accept_to_prefs($httpaccept);
193             $sp = common_accept_to_prefs(PAGE_TYPE_PREFS_MOBILEPROFILE);
194
195             $type = common_negotiate_type($cp, $sp);
196
197             if (!$type) {
198                 // TRANS: Client exception thrown when requesting a not supported media type.
199                 throw new ClientException(_m('This page is not available in a '.
200                                             'media type you accept.'), 406);
201             }
202         //}
203
204         header('Content-Type: '.$type);
205
206         if ($this->reallyMobile) {
207
208            $action->extraHeaders();
209            if (preg_match("/.*\/.*xml/", $type)) {
210                // Required for XML documents
211                $action->xw->startDocument('1.0', 'UTF-8');
212            }
213            $action->xw->writeDTD('html',
214                            '-//WAPFORUM//DTD XHTML Mobile 1.0//EN',
215                            $this->DTD);
216
217             $language = $action->getLanguage();
218
219             $action->elementStart('html', array('xmlns' => 'http://www.w3.org/1999/xhtml',
220                                             'xml:lang' => $language));
221
222             return false;
223
224         } else {
225         return true;
226         }
227
228     }
229
230     function setMobileFeatures($useragent)
231     {
232         $mobiledeviceInputFileType = array(
233             'nokia'
234         );
235
236         $this->mobileFeatures['inputfiletype'] = false;
237
238         foreach ($mobiledeviceInputFileType as $md) {
239             if (strstr($useragent, $md) !== false) {
240                 $this->mobileFeatures['inputfiletype'] = true;
241                 break;
242             }
243         }
244     }
245
246     function onStartShowStatusNetStyles($action)
247     {
248         if (!$this->serveMobile) {
249             return true;
250         }
251
252         $action->primaryCssLink();
253
254         $action->cssLink($this->path('mp-screen.css'),null,'screen');
255         if (file_exists(Theme::file('css/mp-screen.css'))) {
256             $action->cssLink('css/mp-screen.css', null, 'screen');
257         }
258
259         $action->cssLink($this->path('mp-handheld.css'),null,'handheld');
260         if (file_exists(Theme::file('css/mp-handheld.css'))) {
261             $action->cssLink('css/mp-handheld.css', null, 'handheld');
262         }
263
264         // Allow other plugins to load their styles.
265         Event::handle('EndShowStatusNetStyles', array($action));
266         Event::handle('EndShowLaconicaStyles', array($action));
267
268         return false;
269     }
270
271     function onStartShowUAStyles($action) {
272         if (!$this->serveMobile) {
273             return true;
274         }
275
276         return false;
277     }
278
279     function onStartShowHeader($action)
280     {
281         if (!$this->serveMobile) {
282             return true;
283         }
284
285         $action->elementStart('div', array('id' => 'header'));
286         $this->_showLogo($action);
287         $action->showPrimaryNav();
288         $action->elementEnd('div');
289
290         return false;
291     }
292
293     function _showLogo($action)
294     {
295         $action->elementStart('address', 'vcard');
296         if (common_config('singleuser', 'enabled')) {
297             $user = User::singleUser();
298             $url = common_local_url('showstream', array('nickname' => $user->nickname));
299         } else {
300             $url = common_local_url('public');
301         }
302
303         $action->elementStart('a', array('class' => 'url home bookmark',
304                                          'href' => $url));
305
306         if (common_config('site', 'mobilelogo') ||
307             file_exists(Theme::file('logo.png')) ||
308             file_exists(Theme::file('mobilelogo.png'))) {
309
310             $action->element('img', array('class' => 'photo',
311                 'src' => (common_config('site', 'mobilelogo')) ? common_config('site', 'mobilelogo') :
312                             ((file_exists(Theme::file('mobilelogo.png'))) ? (Theme::path('mobilelogo.png')) : Theme::path('logo.png')),
313                 'alt' => common_config('site', 'name')));
314         }
315         $action->element('span', array('class' => 'fn org'), common_config('site', 'name'));
316         $action->elementEnd('a');
317         $action->elementEnd('address');
318     }
319
320     function onStartShowAside($action)
321     {
322         if ($this->serveMobile) {
323             return false;
324         }
325     }
326
327     function onStartShowLocalNavBlock($action)
328     {
329         if ($this->serveMobile) {
330             // @todo FIXME: "Show Navigation" / "Hide Navigation" needs i18n
331             $action->element('a', array('href' => '#', 'id' => 'navtoggle'), 'Show Navigation');
332         return true;
333         }
334     }
335
336     function onEndShowScripts($action)
337     {
338         // @todo FIXME: "Show Navigation" / "Hide Navigation" needs i18n
339         $action->inlineScript('
340             $(function() {
341                 $("#mobile-toggle-disable").click(function() {
342                     $.cookie("MobileOverride", "0", {path: "/"});
343                     window.location.reload();
344                     return false;
345                 });
346                 $("#mobile-toggle-enable").click(function() {
347                     $.cookie("MobileOverride", "1", {path: "/"});
348                     window.location.reload();
349                     return false;
350                 });
351                 $("#navtoggle").click(function () {
352                           $("#site_nav_local_views").fadeToggle();
353                           var text = $("#navtoggle").text();
354                           $("#navtoggle").text(
355                           text == "Show Navigation" ? "Hide Navigation" : "Show Navigation");
356                 });
357             });'
358         );
359
360         if ($this->serveMobile) {
361             $action->inlineScript('
362                 $(function() {
363                         $(".checkbox-wrapper").unbind("click");
364                 });'
365             );
366         }
367
368
369     }
370
371
372     function onEndShowInsideFooter($action)
373     {
374         if ($this->serveMobile) {
375             // TRANS: Link to switch site layout from mobile to desktop mode. Appears at very bottom of page.
376             $linkText = _m('Switch to desktop site layout.');
377             $key = 'mobile-toggle-disable';
378         } else {
379             // TRANS: Link to switch site layout from desktop to mobile mode. Appears at very bottom of page.
380             $linkText = _m('Switch to mobile site layout.');
381             $key = 'mobile-toggle-enable';
382         }
383         $action->elementStart('p');
384         $action->element('a', array('href' => '#', 'id' => $key), $linkText);
385         $action->elementEnd('p');
386         return true;
387     }
388
389     function _common_path($relative, $ssl=false)
390     {
391         $pathpart = (common_config('site', 'path')) ? common_config('site', 'path')."/" : '';
392
393         if (($ssl && (common_config('site', 'ssl') === 'sometimes'))
394             || common_config('site', 'ssl') === 'always') {
395             $proto = 'https';
396             if (is_string(common_config('site', 'sslserver')) &&
397                 mb_strlen(common_config('site', 'sslserver')) > 0) {
398                 $serverpart = common_config('site', 'sslserver');
399             } else {
400                 $serverpart = common_config('site', 'mobileserver');
401             }
402         } else {
403             $proto      = 'http';
404             $serverpart = common_config('site', 'mobileserver');
405         }
406
407         return $proto.'://'.$serverpart.'/'.$pathpart.$relative;
408     }
409
410     function onPluginVersion(&$versions)
411     {
412         $versions[] = array('name' => 'MobileProfile',
413                             'version' => STATUSNET_VERSION,
414                             'author' => 'Sarven Capadisli',
415                             'homepage' => 'http://status.net/wiki/Plugin:MobileProfile',
416                             'rawdescription' =>
417                             // TRANS: Plugin description.
418                             _m('XHTML MobileProfile output for supporting user agents.'));
419         return true;
420     }
421 }