]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/MobileProfile/MobileProfilePlugin.php
Merge branch '1.0.x' into testing
[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                 // TRANS: Client exception thrown when requesting a not supported media type.
197                 throw new ClientException(_m('This page is not available in a '.
198                                             'media type you accept.'), 406);
199             }
200         //}
201
202         header('Content-Type: '.$type);
203
204         $action->extraHeaders();
205         if (preg_match("/.*\/.*xml/", $type)) {
206             // Required for XML documents
207             $action->xw->startDocument('1.0', 'UTF-8');
208         }
209         $action->xw->writeDTD('html',
210                         '-//WAPFORUM//DTD XHTML Mobile 1.0//EN',
211                         $this->DTD);
212
213         $language = $action->getLanguage();
214
215         $action->elementStart('html', array('xmlns' => 'http://www.w3.org/1999/xhtml',
216                                             'xml:lang' => $language));
217
218         return false;
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     function onStartShowStatusNetStyles($action)
238     {
239         if (!$this->serveMobile) {
240             return true;
241         }
242
243         $action->primaryCssLink();
244
245         if (file_exists(Theme::file('css/mp-screen.css'))) {
246             $action->cssLink('css/mp-screen.css', null, 'screen');
247         } else {
248             $action->cssLink($this->path('mp-screen.css'),null,'screen');
249         }
250
251         if (file_exists(Theme::file('css/mp-handheld.css'))) {
252             $action->cssLink('css/mp-handheld.css', null, 'handheld');
253         } else {
254             $action->cssLink($this->path('mp-handheld.css'),null,'handheld');
255         }
256
257         // Allow other plugins to load their styles.
258         Event::handle('EndShowStatusNetStyles', array($action));
259         Event::handle('EndShowLaconicaStyles', array($action));
260
261         return false;
262     }
263
264     function onStartShowUAStyles($action) {
265         if (!$this->serveMobile) {
266             return true;
267         }
268
269         return false;
270     }
271
272     function onStartShowHeader($action)
273     {
274         if (!$this->serveMobile) {
275             return true;
276         }
277
278         $action->elementStart('div', array('id' => 'header'));
279         $this->_showLogo($action);
280         $action->showPrimaryNav();
281         $action->elementEnd('div');
282
283         return false;
284     }
285
286     function _showLogo($action)
287     {
288         $action->elementStart('address', 'vcard');
289         $action->elementStart('a', array('class' => 'url home bookmark',
290                                        'href' => common_local_url('public')));
291         if (common_config('site', 'mobilelogo') ||
292             file_exists(Theme::file('logo.png')) ||
293             file_exists(Theme::file('mobilelogo.png'))) {
294
295             $action->element('img', array('class' => 'photo',
296                 'src' => (common_config('site', 'mobilelogo')) ? common_config('site', 'mobilelogo') :
297                             ((file_exists(Theme::file('mobilelogo.png'))) ? (Theme::path('mobilelogo.png')) : Theme::path('logo.png')),
298                 'alt' => common_config('site', 'name')));
299         }
300         $action->element('span', array('class' => 'fn org'), common_config('site', 'name'));
301         $action->elementEnd('a');
302         $action->elementEnd('address');
303     }
304
305     function onStartShowAside($action)
306     {
307         if ($this->serveMobile) {
308             return false;
309         }
310     }
311
312     function onStartShowLocalNavBlock($action)
313     {
314         if ($this->serveMobile) {
315             // @todo FIXME: "Show Navigation" / "Hide Navigation" needs i18n
316             $action->element('a', array('href' => '#', 'id' => 'navtoggle'), 'Show Navigation');
317         return true;
318         }
319     }
320
321     function onEndShowScripts($action)
322     {
323         // @todo FIXME: "Show Navigation" / "Hide Navigation" needs i18n
324         $action->inlineScript('
325             $(function() {
326                 $("#mobile-toggle-disable").click(function() {
327                     $.cookie("MobileOverride", "0", {path: "/"});
328                     window.location.reload();
329                     return false;
330                 });
331                 $("#mobile-toggle-enable").click(function() {
332                     $.cookie("MobileOverride", "1", {path: "/"});
333                     window.location.reload();
334                     return false;
335                 });
336                 $("#navtoggle").click(function () {
337                           $("#site_nav_local_views").fadeToggle();
338                           var text = $("#navtoggle").text();
339                           $("#navtoggle").text(
340                           text == "Show Navigation" ? "Hide Navigation" : "Show Navigation");
341                 });
342             });'
343         );
344     }
345
346
347     function onEndShowInsideFooter($action)
348     {
349         if ($this->serveMobile) {
350             // TRANS: Link to switch site layout from mobile to desktop mode. Appears at very bottom of page.
351             $linkText = _m('Switch to desktop site layout.');
352             $key = 'mobile-toggle-disable';
353         } else {
354             // TRANS: Link to switch site layout from desktop to mobile mode. Appears at very bottom of page.
355             $linkText = _m('Switch to mobile site layout.');
356             $key = 'mobile-toggle-enable';
357         }
358         $action->elementStart('p');
359         $action->element('a', array('href' => '#', 'id' => $key), $linkText);
360         $action->elementEnd('p');
361         return true;
362     }
363
364     function _common_path($relative, $ssl=false)
365     {
366         $pathpart = (common_config('site', 'path')) ? common_config('site', 'path')."/" : '';
367
368         if (($ssl && (common_config('site', 'ssl') === 'sometimes'))
369             || common_config('site', 'ssl') === 'always') {
370             $proto = 'https';
371             if (is_string(common_config('site', 'sslserver')) &&
372                 mb_strlen(common_config('site', 'sslserver')) > 0) {
373                 $serverpart = common_config('site', 'sslserver');
374             } else {
375                 $serverpart = common_config('site', 'mobileserver');
376             }
377         } else {
378             $proto      = 'http';
379             $serverpart = common_config('site', 'mobileserver');
380         }
381
382         return $proto.'://'.$serverpart.'/'.$pathpart.$relative;
383     }
384
385     function onPluginVersion(&$versions)
386     {
387         $versions[] = array('name' => 'MobileProfile',
388                             'version' => STATUSNET_VERSION,
389                             'author' => 'Sarven Capadisli',
390                             'homepage' => 'http://status.net/wiki/Plugin:MobileProfile',
391                             'rawdescription' =>
392                             // TRANS: Plugin description.
393                             _m('XHTML MobileProfile output for supporting user agents.'));
394         return true;
395     }
396 }