]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/MobileProfile/MobileProfilePlugin.php
Merge branch 'master' of gitorious.org:social/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')) {
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         } elseif (array_key_exists('HTTP_USER_AGENT', $_SERVER)) {
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                     'maemo',
115                     'midp-',
116                     'mobile',
117                     'mot',
118                     'netfront',
119                     'nitro',
120                     'nokia',
121                     'opera mini',
122                     'palm',
123                     'palmsource',
124                     'panasonic',
125                     'philips',
126                     'pocketpc',
127                     'portalmmm',
128                     'rover',
129                     'samsung',
130                     'sanyo',
131                     'series60',
132                     'sharp',
133                     'sie-',
134                     'smartphone',
135                     'sony',
136                     'symbian',
137                     'up.browser',
138                     'up.link',
139                     'up.link',
140                     'vodafone',
141                     'wap1',
142                     'wap2',
143                     'webos',
144                     'windows ce'
145                 );
146
147                 $blacklist = array(
148                     'ipad', // Larger screen handles the full theme fairly well.
149                 );
150
151                 $httpuseragent = strtolower($_SERVER['HTTP_USER_AGENT']);
152
153                 foreach ($blacklist as $md) {
154                     if (strstr($httpuseragent, $md) !== false) {
155                         $this->serveMobile = false;
156                         return true;
157                     }
158                 }
159
160                 foreach ($this->mobiledevices as $md) {
161                     if (strstr($httpuseragent, $md) !== false) {
162                         $this->setMobileFeatures($httpuseragent);
163
164                         $this->serveMobile = true;
165                         $this->reallyMobile = true;
166                         break;
167                     }
168                 }
169             //}
170
171             // If they are okay with MP, and the site has a mobile server,
172             // redirect there
173             if ($this->serveMobile &&
174                 common_config('site', 'mobileserver') !== false &&
175                 (common_config('site', 'mobileserver') !=
176                     common_config('site', 'server'))) {
177
178                 // FIXME: Redirect to equivalent page on mobile site instead
179                 common_redirect($this->_common_path(''), 302);
180             }
181         }
182
183         if (!$this->serveMobile) {
184             return true;
185         }
186
187         // @fixme $type is undefined, making this if case useless and spewing errors.
188         // What's the intent?
189         //if (!$type) {
190             $httpaccept = isset($_SERVER['HTTP_ACCEPT']) ?
191               $_SERVER['HTTP_ACCEPT'] : null;
192
193             $cp = common_accept_to_prefs($httpaccept);
194             $sp = common_accept_to_prefs(PAGE_TYPE_PREFS_MOBILEPROFILE);
195
196             $type = common_negotiate_type($cp, $sp);
197
198             if (!$type) {
199                 // TRANS: Client exception thrown when requesting a not supported media type.
200                 throw new ClientException(_m('This page is not available in a '.
201                                             'media type you accept.'), 406);
202             }
203         //}
204
205         header('Content-Type: '.$type);
206
207         if ($this->reallyMobile) {
208
209            $action->extraHeaders();
210            if (preg_match("/.*\/.*xml/", $type)) {
211                // Required for XML documents
212                $action->startXML();
213            }
214            $action->xw->writeDTD('html',
215                            '-//WAPFORUM//DTD XHTML Mobile 1.0//EN',
216                            $this->DTD);
217
218             $language = $action->getLanguage();
219
220             $action->elementStart('html', array('xmlns' => 'http://www.w3.org/1999/xhtml',
221                                             'xml:lang' => $language));
222
223             return false;
224
225         } else {
226         return true;
227         }
228
229     }
230
231     function setMobileFeatures($useragent)
232     {
233         $mobiledeviceInputFileType = array(
234             'nokia'
235         );
236
237         $this->mobileFeatures['inputfiletype'] = false;
238
239         foreach ($mobiledeviceInputFileType as $md) {
240             if (strstr($useragent, $md) !== false) {
241                 $this->mobileFeatures['inputfiletype'] = true;
242                 break;
243             }
244         }
245     }
246
247     public function onStartShowStylesheets(Action $action)
248     {
249         if (!$this->serveMobile) {
250             return true;
251         }
252
253         $action->primaryCssLink();
254
255         $action->cssLink($this->path('mp-screen.css'),null,'screen');
256         if (file_exists(Theme::file('css/mp-screen.css'))) {
257             $action->cssLink('css/mp-screen.css', null, 'screen');
258         }
259
260         $action->cssLink($this->path('mp-handheld.css'),null,'handheld');
261         if (file_exists(Theme::file('css/mp-handheld.css'))) {
262             $action->cssLink('css/mp-handheld.css', null, 'handheld');
263         }
264
265         // Allow other plugins to load their styles.
266         Event::handle('EndShowStylesheets', 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');
296         if (common_config('singleuser', 'enabled')) {
297             $user = User::singleUser();
298             $url = common_local_url('showstream', array('nickname' => $user->getNickname()));
299         } else {
300             $url = common_local_url('public');
301         }
302
303         $action->elementStart('a', array('class' => 'h-card 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' => 'u-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->elementEnd('a');
316         $action->elementEnd('address');
317     }
318
319     function onStartShowAside($action)
320     {
321         if ($this->serveMobile) {
322             return false;
323         }
324     }
325
326     function onStartShowLocalNavBlock($action)
327     {
328         if ($this->serveMobile) {
329             // @todo FIXME: "Show Navigation" / "Hide Navigation" needs i18n
330             $action->element('a', array('href' => '#', 'id' => 'navtoggle'), 'Show Navigation');
331         return true;
332         }
333     }
334
335     function onEndShowScripts(Action $action)
336     {
337         // @todo FIXME: "Show Navigation" / "Hide Navigation" needs i18n
338         $action->inlineScript('
339             $(function() {
340                 $("#mobile-toggle-disable").click(function() {
341                     $.cookie("MobileOverride", "0", {path: "/"});
342                     window.location.reload();
343                     return false;
344                 });
345                 $("#mobile-toggle-enable").click(function() {
346                     $.cookie("MobileOverride", "1", {path: "/"});
347                     window.location.reload();
348                     return false;
349                 });
350                 $("#navtoggle").click(function () {
351                           $("#site_nav_local_views").fadeToggle();
352                           var text = $("#navtoggle").text();
353                           $("#navtoggle").text(
354                           text == "Show Navigation" ? "Hide Navigation" : "Show Navigation");
355                 });
356             });'
357         );
358
359         if ($this->serveMobile) {
360             $action->inlineScript('
361                 $(function() {
362                         $(".checkbox-wrapper").unbind("click");
363                 });'
364             );
365         }
366
367
368     }
369
370
371     function onEndShowInsideFooter($action)
372     {
373         if ($this->serveMobile) {
374             // TRANS: Link to switch site layout from mobile to desktop mode. Appears at very bottom of page.
375             $linkText = _m('Switch to desktop site layout.');
376             $key = 'mobile-toggle-disable';
377         } else {
378             // TRANS: Link to switch site layout from desktop to mobile mode. Appears at very bottom of page.
379             $linkText = _m('Switch to mobile site layout.');
380             $key = 'mobile-toggle-enable';
381         }
382         $action->elementStart('p');
383         $action->element('a', array('href' => '#', 'id' => $key), $linkText);
384         $action->elementEnd('p');
385         return true;
386     }
387
388     function _common_path($relative, $ssl=false)
389     {
390         $pathpart = (common_config('site', 'path')) ? common_config('site', 'path')."/" : '';
391
392         if (($ssl && (common_config('site', 'ssl') === 'sometimes'))
393             || common_config('site', 'ssl') === 'always') {
394             $proto = 'https';
395             if (is_string(common_config('site', 'sslserver')) &&
396                 mb_strlen(common_config('site', 'sslserver')) > 0) {
397                 $serverpart = common_config('site', 'sslserver');
398             } else {
399                 $serverpart = common_config('site', 'mobileserver');
400             }
401         } else {
402             $proto      = 'http';
403             $serverpart = common_config('site', 'mobileserver');
404         }
405
406         return $proto.'://'.$serverpart.'/'.$pathpart.$relative;
407     }
408
409     function onPluginVersion(array &$versions)
410     {
411         $versions[] = array('name' => 'MobileProfile',
412                             'version' => GNUSOCIAL_VERSION,
413                             'author' => 'Sarven Capadisli',
414                             'homepage' => 'http://status.net/wiki/Plugin:MobileProfile',
415                             'rawdescription' =>
416                             // TRANS: Plugin description.
417                             _m('XHTML MobileProfile output for supporting user agents.'));
418         return true;
419     }
420 }