/
Router.php
387 lines (344 loc) · 11.1 KB
/
Router.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
<?php
namespace HSPDev\HuaweiApi;
/*
* Depends on:
* HSPDev\HuaweiApi\CustomHttpClient
*/
/**
* This class handles login, sessions and such.
* and provides relevant methods for getting at the details.
* This has probably become quite a god object, but it's nice to use.
*/
class Router
{
private $http = null; //Our custom HTTP provider.
private $routerAddress = 'http://192.168.8.1'; //This is the one for the router I got.
//These two we need to acquire through an API call.
private $sessionInfo = '';
private $tokenInfo = '';
public function __construct()
{
$this->http = new CustomHttpClient();
}
/**
* Sets the router address.
*/
public function setAddress($address)
{
//Remove trailing slash if any.
$address = rtrim($address, '/');
//If not it starts with http, we assume HTTP and add it.
if (strpos($address, 'http') !== 0) {
$address = 'http://'.$address;
}
$this->routerAddress = $address;
}
/**
* Most API responses are just simple XML, so to avoid repetition
* this function will GET the route and return the object.
*
* @return SimpleXMLElement
*/
public function generalizedGet($route)
{
//Makes sure we are ready for the next request.
$this->prepare();
$xml = $this->http->get($this->getUrl($route));
$obj = new \SimpleXMLElement($xml);
//Check for error message
if (property_exists($obj, 'code')) {
throw new \UnexpectedValueException('The API returned error code: '.$obj->code);
}
return $obj;
}
/**
* Gets the current router status.
*
* @return SimpleXMLElement
*/
public function getStatus()
{
return $this->generalizedGet('api/monitoring/status');
}
/**
* Gets traffic statistics (numbers are in bytes).
*
* @return SimpleXMLElement
*/
public function getTrafficStats()
{
return $this->generalizedGet('api/monitoring/traffic-statistics');
}
/**
* Gets monthly statistics (numbers are in bytes)
* This probably only works if you have setup a limit.
*
* @return SimpleXMLElement
*/
public function getMonthStats()
{
return $this->generalizedGet('api/monitoring/month_statistics');
}
/**
* Info about the current mobile network. (PLMN info).
*
* @return SimpleXMLElement
*/
public function getNetwork()
{
return $this->generalizedGet('api/net/current-plmn');
}
/**
* Gets the current craddle status.
*
* @return SimpleXMLElement
*/
public function getCraddleStatus()
{
return $this->generalizedGet('api/cradle/status-info');
}
/**
* Get current SMS count.
*
* @return SimpleXMLElement
*/
public function getSmsCount()
{
return $this->generalizedGet('api/sms/sms-count');
}
/**
* Get current WLAN Clients.
*
* @return SimpleXMLElement
*/
public function getWlanClients()
{
return $this->generalizedGet('api/wlan/host-list');
}
/**
* Get notifications on router.
*
* @return SimpleXMLElement
*/
public function getNotifications()
{
return $this->generalizedGet('api/monitoring/check-notifications');
}
/**
* Gets the SMS inbox.
* Page parameter is NOT null indexed and starts at 1.
* I don't know if there is an upper limit on $count. Your milage may vary.
* unreadPrefered should give you unread messages first.
*
* @return bool
*/
public function setLedOn($on = false)
{
//Makes sure we are ready for the next request.
$this->prepare();
$ledXml = '<?xml version:"1.0" encoding="UTF-8"?><request><ledSwitch>'.($on ? '1' : '0').'</ledSwitch></request>';
$xml = $this->http->postXml($this->getUrl('api/led/circle-switch'), $ledXml);
$obj = new \SimpleXMLElement($xml);
//Simple check if login is OK.
return (string) $obj == 'OK';
}
/**
* Checks whatever we are logged in.
*
* @return bool
*/
public function getLedStatus()
{
$obj = $this->generalizedGet('api/led/circle-switch');
if (property_exists($obj, 'ledSwitch')) {
if ($obj->ledSwitch == '1') {
return true;
}
}
return false;
}
/**
* Checks whatever we are logged in.
*
* @return bool
*/
public function isLoggedIn()
{
$obj = $this->generalizedGet('api/user/state-login');
if (property_exists($obj, 'State')) {
/*
* Logged out seems to be -1
* Logged in seems to be 0.
* What the hell?
*/
if ($obj->State == '0') {
return true;
}
}
return false;
}
/**
* Gets the SMS inbox.
* Page parameter is NOT null indexed and starts at 1.
* I don't know if there is an upper limit on $count. Your milage may vary.
* unreadPrefered should give you unread messages first.
*
* @return SimpleXMLElement
*/
public function getInbox($page = 1, $count = 20, $unreadPreferred = false)
{
//Makes sure we are ready for the next request.
$this->prepare();
$inboxXml = '<?xml version="1.0" encoding="UTF-8"?><request>
<PageIndex>'.$page.'</PageIndex>
<ReadCount>'.$count.'</ReadCount>
<BoxType>1</BoxType>
<SortType>0</SortType>
<Ascending>0</Ascending>
<UnreadPreferred>'.($unreadPreferred ? '1' : '0').'</UnreadPreferred>
</request>
';
$xml = $this->http->postXml($this->getUrl('api/sms/sms-list'), $inboxXml);
$obj = new \SimpleXMLElement($xml);
return $obj;
}
/**
* Deletes an SMS by ID, also called "Index".
* The index on the Message object you get from getInbox
* will contain an "Index" property with a value like "40000" and up.
* Note: Will return true if the Index DOES NOT exist already.
*
* @return bool
*/
public function deleteSms($index)
{
//Makes sure we are ready for the next request.
$this->prepare();
$deleteXml = '<?xml version="1.0" encoding="UTF-8"?><request>
<Index>'.$index.'</Index>
</request>
';
$xml = $this->http->postXml($this->getUrl('api/sms/delete-sms'), $deleteXml);
$obj = new \SimpleXMLElement($xml);
//Simple check if login is OK.
return (string) $obj == 'OK';
}
/**
* Sends SMS to specified receiver. I don't know if it works for foreign numbers,
* but for local numbers you can just specifiy the number like you would normally
* call it and it should work, here in Denmark "42952777" etc (mine).
* Message parameter got the normal SMS restrictions you know and love.
*
* @return bool
*/
public function sendSms($receiver, $message)
{
//Makes sure we are ready for the next request.
$this->prepare();
/*
* Note how it wants the length of the content also.
* It ALSO wants the current date/time wtf? Oh well..
*/
$sendSmsXml = '<?xml version="1.0" encoding="UTF-8"?><request>
<Index>-1</Index>
<Phones>
<Phone>'.$receiver.'</Phone>
</Phones>
<Sca/>
<Content>'.$message.'</Content>
<Length>'.strlen($message).'</Length>
<Reserved>1</Reserved>
<Date>'.date('Y-m-d H:i:s').'</Date>
<SendType>0</SendType>
</request>
';
$xml = $this->http->postXml($this->getUrl('api/sms/send-sms'), $sendSmsXml);
$obj = new \SimpleXMLElement($xml);
//Simple check if login is OK.
return (string) $obj == 'OK';
}
/**
* Not all methods may work if you don't login.
* Please note that the router is pretty aggressive
* at timing your session out.
* Call something periodically or just relogin on error.
*
* @return bool
*/
public function login($username, $password)
{
//Makes sure we are ready for the next request.
$this->prepare();
/*
* Note how the router wants the password to be the following:
* 1) Hashed by SHA256, then the raw output base64 encoded.
* 2) The username is appended with the result of the above,
* AND the current token. Yes, the password changes everytime
* depending on what token we got. This really fucks with scrapers.
* 3) The string from above (point 2) is then hashed by SHA256 again,
* and the raw output is once again base64 encoded.
*
* This is how the router login process works. So the password being sent
* changes everytime depending on the current user session/token.
* Not bad actually.
*/
$loginXml = '<?xml version="1.0" encoding="UTF-8"?><request>
<Username>'.$username.'</Username>
<password_type>4</password_type>
<Password>'.base64_encode(hash('sha256', $username.base64_encode(hash('sha256', $password, false)).$this->http->getToken(), false)).'</Password>
</request>
';
$xml = $this->http->postXml($this->getUrl('api/user/login'), $loginXml);
$obj = new \SimpleXMLElement($xml);
//Simple check if login is OK.
return (string) $obj == 'OK';
}
/**
* Sets the data switch to enable or disable the mobile connection.
*
* @return bool
*/
public function setDataSwitch($value)
{
if (is_int($value) === false) {
throw new \Exception('Parameter can only be integer.');
}
if ($value !== 0 && $value !== 1) {
throw new \Exception('Parameter can only be integer.');
}
//Makes sure we are ready for the next request.
$this->prepare();
$dataSwitchXml = '<?xml version="1.0" encoding="UTF-8"?><request><dataswitch>'.$value.'</dataswitch></request>';
$xml = $this->http->postXml($this->getUrl('api/dialup/mobile-dataswitch'), $dataSwitchXml);
$obj = new \SimpleXMLElement($xml);
//Simple check if login is OK.
return (string) $obj == 'OK';
}
/**
* Internal helper that lets us build the complete URL
* to a given route in the API.
*
* @return string
*/
private function getUrl($route)
{
return $this->routerAddress.'/'.$route;
}
/**
* Makes sure that we are ready for API usage.
*/
private function prepare()
{
//Check to see if we have session / token.
if (strlen($this->sessionInfo) == 0 || strlen($this->tokenInfo) == 0) {
//We don't have any. Grab some.
$xml = $this->http->get($this->getUrl('api/webserver/SesTokInfo'));
$obj = new \SimpleXMLElement($xml);
if (!property_exists($obj, 'SesInfo') || !property_exists($obj, 'TokInfo')) {
throw new \RuntimeException('Malformed XML returned. Missing SesInfo or TokInfo nodes.');
}
//Set it for future use.
$this->http->setSecurity($obj->SesInfo, $obj->TokInfo);
}
}
}