1 //
2 // Copyright (C) 2020 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #include "host/commands/modem_simulator/call_service.h"
17 
18 #include <android-base/logging.h>
19 
20 #include <chrono>
21 #include <iostream>
22 #include <thread>
23 
24 #include "host/commands/modem_simulator/nvram_config.h"
25 
26 namespace cuttlefish {
27 
CallService(int32_t service_id,ChannelMonitor * channel_monitor,ThreadLooper * thread_looper)28 CallService::CallService(int32_t service_id, ChannelMonitor* channel_monitor,
29                          ThreadLooper* thread_looper)
30     : ModemService(service_id, this->InitializeCommandHandlers(),
31                    channel_monitor, thread_looper) {
32   InitializeServiceState();
33 }
34 
InitializeServiceState()35 void CallService::InitializeServiceState() {
36   auto nvram_config = NvramConfig::Get();
37   auto instance = nvram_config->ForInstance(service_id_);
38   in_emergency_mode_ = instance.emergency_mode();
39 
40   mute_on_ = false;
41 }
42 
SetupDependency(SimService * sim,NetworkService * net)43 void CallService::SetupDependency(SimService* sim, NetworkService* net) {
44   sim_service_ = sim;
45   network_service_ = net;
46 }
47 
InitializeCommandHandlers()48 std::vector<CommandHandler> CallService::InitializeCommandHandlers() {
49   std::vector<CommandHandler> command_handlers = {
50       CommandHandler("D",
51                      [this](const Client& client, std::string& cmd) {
52                        this->HandleDial(client, cmd);
53                      }),
54       CommandHandler(
55           "A",
56           [this](const Client& client) { this->HandleAcceptCall(client); }),
57       CommandHandler(
58           "H",
59           [this](const Client& client) { this->HandleRejectCall(client); }),
60       CommandHandler(
61           "+CLCC",
62           [this](const Client& client) { this->HandleCurrentCalls(client); }),
63       CommandHandler("+CHLD=",
64                      [this](const Client& client, std::string& cmd) {
65                        this->HandleHangup(client, cmd);
66                      }),
67       CommandHandler("+CMUT",
68                      [this](const Client& client, std::string& cmd) {
69                        this->HandleMute(client, cmd);
70                      }),
71       CommandHandler("+VTS=",
72                      [this](const Client& client, std::string& cmd) {
73                        this->HandleSendDtmf(client, cmd);
74                      }),
75       CommandHandler("+CUSD=",
76                      [this](const Client& client, std::string& cmd) {
77                        this->HandleCancelUssd(client, cmd);
78                      }),
79       CommandHandler("+WSOS=0",
80                      [this](const Client& client, std::string& cmd) {
81                        this->HandleEmergencyMode(client, cmd);
82                      }),
83       CommandHandler("+REMOTECALL",
84                      [this](const Client& client, std::string& cmd) {
85                        this->HandleRemoteCall(client, cmd);
86                      }),
87   };
88   return (command_handlers);
89 }
90 
91 // This also resumes held calls
SimulatePendingCallsAnswered()92 void CallService::SimulatePendingCallsAnswered() {
93   for (auto& iter : active_calls_) {
94     if (iter.second.isCallDialing()) {
95       iter.second.SetCallActive();
96     }
97   }
98 }
99 
TimerWaitingRemoteCallResponse(CallToken call_token)100 void CallService::TimerWaitingRemoteCallResponse(CallToken call_token) {
101   LOG(DEBUG) << "Dialing id: " << call_token.first
102              << ", number: " << call_token.second << "timeout, cancel";
103   auto iter = active_calls_.find(call_token.first);
104   if (iter != active_calls_.end() && iter->second.number == call_token.second) {
105     if (iter->second.remote_client != std::nullopt) {
106       CloseRemoteConnection(*(iter->second.remote_client));
107     }
108     active_calls_.erase(iter);  // match
109     CallStateUpdate();
110   }  // else not match, ignore
111 }
112 
113 /* ATD */
HandleDial(const Client & client,const std::string & command)114 void CallService::HandleDial(const Client& client, const std::string& command) {
115   // Check the network registration state
116   auto registration_state = NetworkService::NET_REGISTRATION_UNKNOWN;
117   if (network_service_) {
118     registration_state = network_service_->GetVoiceRegistrationState();
119   }
120 
121   bool emergency_only = false;
122   if (registration_state == NetworkService::NET_REGISTRATION_HOME ||
123       registration_state == NetworkService::NET_REGISTRATION_ROAMING) {
124     emergency_only = false;
125   } else if (registration_state == NetworkService::NET_REGISTRATION_EMERGENCY) {
126     emergency_only = true;
127   } else {
128     client.SendCommandResponse(kCmeErrorNoNetworkService);
129     return;
130   }
131 
132   CommandParser cmd(command);
133   cmd.SkipPrefixAT();
134 
135   std::string number;
136   bool emergency_number = false;
137   /**
138    * Normal dial:     ATDnumber[clir];
139    * Emergency dial:  ATDnumber@[category],#[clir];
140    */
141   auto pos = cmd->find_last_of('@');
142   if (pos != std::string_view::npos) {
143     emergency_number = true;
144     number = cmd->substr(1, pos -1); // Skip 'D' and ignore category, clir
145   } else {  // Remove 'i' or 'I' or ';'
146     pos = cmd->find_last_of('i');
147     if (pos == std::string_view::npos) {
148       pos = cmd->find_last_of('I');
149       if (pos == std::string_view::npos) {
150         pos = cmd->find_last_of(';');
151       }
152     }
153     if (pos == std::string_view::npos) {
154       number = cmd->substr(1);
155     } else {
156       number = cmd->substr(1, pos -1);
157     }
158   }
159 
160   // Check the number is valid digits or not
161   if (strspn(number.c_str(), "1234567890") != number.size()) {
162     client.SendCommandResponse(kCmeErrorInCorrectParameters);
163     return;
164   }
165 
166   if (emergency_only && !emergency_number) {
167     client.SendCommandResponse(kCmeErrorNetworkNotAllowedEmergencyCallsOnly);
168     return;
169   }
170 
171   // If the number is not emergency number, FDN enabled and the number is not in
172   // the fdn list, return kCmeErrorFixedDialNumberOnlyAllowed.
173   if (!emergency_number && sim_service_->IsFDNEnabled() &&
174       !sim_service_->IsFixedDialNumber(number)) {
175     client.SendCommandResponse(kCmeErrorFixedDialNumberOnlyAllowed);
176     return;
177   }
178 
179   int port = 0;
180   if (number.length() == 11) {
181     port = std::stoi(number.substr(7));
182   } else if (number.length() == 4) {
183     port = std::stoi(number);
184   }
185 
186   if (port >= kRemotePortRange.first &&
187       port <= kRemotePortRange.second) {  // May be a remote call
188     std::stringstream ss;
189     ss << port;
190     auto remote_port = ss.str();
191     auto remote_client = ConnectToRemoteCvd(remote_port);
192     auto client_id = ClientId();
193     if (!remote_client->IsOpen()) {
194       client.SendCommandResponse(kCmeErrorNoNetworkService);
195       return;
196     }
197     auto local_host_port = GetHostId();
198     if (local_host_port == remote_port) {
199       client.SendCommandResponse(kCmeErrorOperationNotAllowed);
200       return;
201     }
202 
203     if (channel_monitor_) {
204       client_id = channel_monitor_->SetRemoteClient(remote_client, false);
205     }
206 
207     ss.clear();
208     ss.str("");
209     ss << "AT+REMOTECALL=4,0,0,\"" << local_host_port << "\",129";
210 
211     SendCommandToRemote(client_id, "REM0");
212     SendCommandToRemote(client_id, ss.str());
213 
214     CallStatus call_status(remote_port);
215     call_status.is_remote_call = true;
216     call_status.is_mobile_terminated = false;
217     call_status.call_state = CallStatus::CALL_STATE_DIALING;
218     call_status.remote_client = client_id;
219     auto index = FindFreeCallIndex();
220 
221     auto call_token = std::make_pair(index, call_status.number);
222     call_status.timeout_serial = thread_looper_->Post(
223         makeSafeCallback<CallService>(this,
224                                       [call_token](CallService* me) {
225                                         me->TimerWaitingRemoteCallResponse(
226                                             call_token);
227                                       }),
228         std::chrono::minutes(1));
229 
230     active_calls_[index] = call_status;
231   } else {
232     CallStatus call_status(number);
233     call_status.is_mobile_terminated = false;
234     call_status.call_state = CallStatus::CALL_STATE_DIALING;
235     auto index = FindFreeCallIndex();
236     active_calls_[index] = call_status;
237 
238     if (emergency_number) {
239       in_emergency_mode_ = true;
240       SendUnsolicitedCommand("+WSOS: 1");
241     }
242     thread_looper_->Post(
243         makeSafeCallback(this, &CallService::SimulatePendingCallsAnswered),
244         std::chrono::seconds(1));
245   }
246 
247   client.SendCommandResponse("OK");
248   std::this_thread::sleep_for(std::chrono::seconds(2));
249 }
250 
SendCallStatusToRemote(CallStatus & call,CallStatus::CallState state)251 void CallService::SendCallStatusToRemote(CallStatus& call,
252                                          CallStatus::CallState state) {
253   if (call.is_remote_call && call.remote_client != std::nullopt) {
254     std::stringstream ss;
255     ss << "AT+REMOTECALL=" << state << "," << call.is_voice_mode << ","
256        << call.is_multi_party << ",\"" << GetHostId() << "\","
257        << call.is_international;
258 
259     SendCommandToRemote(*(call.remote_client), ss.str());
260     if (state == CallStatus::CALL_STATE_HANGUP) {
261       CloseRemoteConnection(*(call.remote_client));
262     }
263   }
264 }
265 
266 /* ATA */
HandleAcceptCall(const Client & client)267 void CallService::HandleAcceptCall(const Client& client) {
268   for (auto& iter : active_calls_) {
269     if (iter.second.isCallIncoming()) {
270       iter.second.SetCallActive();
271       SendCallStatusToRemote(iter.second, CallStatus::CALL_STATE_ACTIVE);
272     } else if (iter.second.isCallActive()) {
273       iter.second.SetCallBackground();
274       SendCallStatusToRemote(iter.second, CallStatus::CALL_STATE_HELD);
275     }
276   }
277 
278   client.SendCommandResponse("OK");
279 }
280 
281 /* ATH */
HandleRejectCall(const Client & client)282 void CallService::HandleRejectCall(const Client& client) {
283   for (auto iter = active_calls_.begin(); iter != active_calls_.end();) {
284     /* ATH: hangup, since user is busy */
285     if (iter->second.isCallIncoming()) {
286       SendCallStatusToRemote(iter->second, CallStatus::CALL_STATE_HANGUP);
287       iter = active_calls_.erase(iter);
288     } else {
289       ++iter;
290     }
291   }
292 
293   client.SendCommandResponse("OK");
294 }
295 
296 /**
297  * AT+CLCC
298  *   Returns list of current calls of MT. If command succeeds but no
299  *   calls are available, no information response is sent to TE.
300  *
301  *   command             Possible response(s)
302  *   AT+CLCC               [+CLCC: <ccid1>,<dir>,<stat>,<mode>,<mpty>
303  *                         [,<number>,<type>[,<alpha>[,<priority>
304  *                         [,<CLI validity>]]]][<CR><LF>
305  *                         +CLCC: <ccid2>,<dir>,<stat>,<mode>,<mpty>
306  *                         [,<number>,<type>[,<alpha>[,<priority>[,<CLI validity>]]]]
307  *                         +CME ERROR: <err>
308  *
309  * <ccidx>: integer type. This number can be used in +CHLD command
310  * operations. Value range is from 1 to N. N, the maximum number of
311  * simultaneous call control processes is implementation specific.
312  * <dir>: integer type
313  *       0 mobile originated (MO) call
314          1 mobile terminated (MT) call
315  * <stat>: integer type (state of the call)
316  *       0 active
317  *       1 held
318  *       2 dialing (MO call)
319  *       3 alerting (MO call)
320  *       4 incoming (MT call)
321  *       5 waiting (MT call)
322  * <mode>: integer type (bearer/teleservice)
323  *       0 voice
324  *       1 data
325  *       2 fax
326  *       3 voice followed by data, voice mode
327  *       4 alternating voice/data, voice mode
328  *       5 alternating voice/fax, voice mode
329  *       6 voice followed by data, data mode
330  *       7 alternating voice/data, data mode
331  *       8 alternating voice/fax, fax mode
332  *       9 unknown
333  * <mpty>: integer type
334  *       0 call is not one of multiparty (conference) call parties
335  *       1 call is one of multiparty (conference) call parties
336  * <number>: string type phone number in format specified by <type>.
337  * <type>: type of address octet in integer format
338  *
339  *see RIL_REQUEST_GET_CURRENT_CALLS in RIL
340  */
HandleCurrentCalls(const Client & client)341 void CallService::HandleCurrentCalls(const Client& client) {
342   std::vector<std::string> responses;
343   std::stringstream ss;
344 
345   // AT+CLCC
346   // [+CLCC: <ccid1>,<dir>,<stat>,<mode>,<mpty>[,<number>,<type>[,<alpha>[,<priority>[,<CLI validity>]]]]
347   // [+CLCC: <ccid2>,<dir>,<stat>,<mode>,<mpty>[,<number>,<type>[,<alpha>[,<priority>[,<CLI validity>]]]]
348   // [...]]]
349   for (auto iter = active_calls_.begin(); iter != active_calls_.end(); ++iter) {
350     int index = iter->first;
351     int dir = iter->second.is_mobile_terminated;
352     CallStatus::CallState call_state = iter->second.call_state;
353     int mode = iter->second.is_voice_mode;
354     int mpty = iter->second.is_multi_party;
355     int type = iter->second.is_international ? 145 : 129;
356     std::string number = iter->second.number;
357 
358     ss.clear();
359     ss << "+CLCC: " << index << "," << dir << "," << call_state << ","
360         << mode << "," << mpty << "," << number<<  "," << type;
361     responses.push_back(ss.str());
362     ss.str("");
363   }
364 
365   responses.push_back("OK");
366   client.SendCommandResponse(responses);
367 }
368 
369 /**
370  * AT+CHLD
371  *   This command allows the control of the following call related services:
372  *   1) a call can be temporarily disconnected from the MT but the connection
373  *      is retained by the network;
374  *   2) multiparty conversation (conference calls);
375  *   3) the served subscriber who has two calls (one held and the other
376  *     either active or alerting) can connect the other parties and release
377  *     the served subscriber's own connection.
378  *
379  *   Calls can be put on hold, recovered, released, added to conversation,
380  *   and transferred similarly.
381  *
382  *   command             Possible response(s)
383  *   +CHLD=<n>           +CME ERROR: <err>
384  *
385  *   +CHLD=?             +CHLD: (list of supported <n>s)
386  *   e.g. +CHLD: (0,1,1x,2,2x,3,4)
387  *
388  *
389  * see RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND
390  *     RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND
391  *     RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE
392  *     RIL_REQUEST_CONFERENCE
393  *     RIL_REQUEST_SEPARATE_CONNECTION
394  *     RIL_REQUEST_HANGUP
395  *     RIL_REQUEST_UDUB in RIL
396  */
HandleHangup(const Client & client,const std::string & command)397 void CallService::HandleHangup(const Client& client,
398                                const std::string& command) {
399   std::vector<std::string> responses;
400   CommandParser cmd(command);
401   cmd.SkipPrefix();
402 
403   std::string action(*cmd);
404   int n = std::stoi(action.substr(0, 1));
405   int index = -1;
406   if (cmd->length() > 1) {
407     index = std::stoi(action.substr(1));
408   }
409 
410   switch (n) {
411     case 0:  // Release all held calls or set User Determined User Busy(UDUB) for a waiting call
412       for (auto iter = active_calls_.begin(); iter != active_calls_.end();) {
413         if (iter->second.isCallIncoming() ||
414             iter->second.isCallBackground() ||
415             iter->second.isCallWaiting()) {
416           SendCallStatusToRemote(iter->second, CallStatus::CALL_STATE_HANGUP);
417           iter = active_calls_.erase(iter);
418         } else {
419           ++iter;
420         }
421       }
422       break;
423     case 1:
424       if (index == -1) {  // Release all active calls and accepts the other(hold or waiting) call
425         for (auto iter = active_calls_.begin(); iter != active_calls_.end();) {
426           if (iter->second.isCallActive()) {
427             SendCallStatusToRemote(iter->second, CallStatus::CALL_STATE_HANGUP);
428             iter = active_calls_.erase(iter);
429             continue;
430           } else if (iter->second.isCallBackground() ||
431               iter->second.isCallWaiting()) {
432             iter->second.SetCallActive();
433             SendCallStatusToRemote(iter->second, CallStatus::CALL_STATE_ACTIVE);
434           }
435           ++iter;
436         }
437       } else {  // Release a specific active call
438         auto iter = active_calls_.find(index);
439         if (iter != active_calls_.end()) {
440           SendCallStatusToRemote(iter->second, CallStatus::CALL_STATE_HANGUP);
441           active_calls_.erase(iter);
442         }
443       }
444       break;
445     case 2:
446       if (index == -1) {  // Place all active calls and the waiting calls, activates all held calls
447         for (auto& iter : active_calls_) {
448           if (iter.second.isCallActive() || iter.second.isCallWaiting()) {
449             iter.second.SetCallBackground();
450             SendCallStatusToRemote(iter.second, CallStatus::CALL_STATE_HELD);
451           } else if (iter.second.isCallBackground()) {
452             iter.second.SetCallActive();
453             SendCallStatusToRemote(iter.second, CallStatus::CALL_STATE_ACTIVE);
454           }
455         }
456       } else {  // Disconnect a call from the conversation
457         auto iter = active_calls_.find(index);
458         if (iter != active_calls_.end()) {
459           SendCallStatusToRemote(iter->second, CallStatus::CALL_STATE_HANGUP);
460           active_calls_.erase(iter);
461         }
462       }
463       break;
464     case 3:  // Adds an held call to the conversation
465       for (auto iter = active_calls_.begin(); iter != active_calls_.end(); ++iter) {
466         if (iter->second.isCallBackground()) {
467           iter->second.SetCallActive();
468           SendCallStatusToRemote(iter->second, CallStatus::CALL_STATE_ACTIVE);
469         }
470       }
471       break;
472     case 4:  // Connect the two calls
473       for (auto iter = active_calls_.begin(); iter != active_calls_.end(); ++iter) {
474         if (iter->second.isCallBackground()) {
475           iter->second.SetCallActive();
476           SendCallStatusToRemote(iter->second, CallStatus::CALL_STATE_ACTIVE);
477         }
478       }
479       break;
480     default:
481       client.SendCommandResponse(kCmeErrorOperationNotAllowed);
482       return;
483   }
484   client.SendCommandResponse("OK");
485 }
486 
487 /**
488  * AT+CMUT
489  *   This command is used to enable and disable the uplink voice muting
490  * during a voice call.
491  *   Read command returns the current value of <n>.
492  *
493  * Command          Possible response(s)
494  * +CMUT=[<n>]        +CME ERROR: <err>
495  * +CMUT?             +CMUT: <n>
496  *                    +CME ERROR: <err>
497  *
498  * <n>: integer type
499  *   0 mute off
500  *   1 mute on
501  *
502  * see RIL_REQUEST_SET_MUTE or RIL_REQUEST_GET_MUTE in RIL
503  */
HandleMute(const Client & client,const std::string & command)504 void CallService::HandleMute(const Client& client, const std::string& command) {
505   std::vector<std::string> responses;
506   std::stringstream ss;
507 
508   CommandParser cmd(command);
509   cmd.SkipPrefix();  // If AT+CMUT?, it remains AT+CMUT?
510 
511   if (cmd == "AT+CMUT?") {
512     ss << "+CMUT: " << mute_on_;
513     responses.push_back(ss.str());
514   } else {  // AT+CMUT = <n>
515     int n = cmd.GetNextInt();
516     switch (n) {
517       case 0:  // Mute off
518         mute_on_ = false;
519         break;
520       case 1:  // Mute on
521         mute_on_ = true;
522         break;
523       default:
524         client.SendCommandResponse(kCmeErrorInCorrectParameters);
525         return;
526     }
527   }
528   responses.push_back("OK");
529   client.SendCommandResponse(responses);
530 }
531 
532 /**
533  * AT+VTS
534  *   This command transmits DTMF, after a successful call connection.
535  * Setting Command is used to send one or more ASCII characters which make
536  * MSC (Mobile Switching Center) send DTMF tone to remote User.
537  *
538  * Command                         Possible response(s)
539  * AT+VTS=<dtmf>[,<duration>]        +CME ERROR: <err>
540  *
541  * <dtmf>
542  *   A single ASCII character in the set { 0 -9, #, *, A – D}.
543  * <duration>
544  *   Refer to duration value range of +VTD command
545  *
546  * see RIL_REQUEST_DTMF in RIL
547  */
HandleSendDtmf(const Client & client,const std::string &)548 void CallService::HandleSendDtmf(const Client& client,
549                                  const std::string& /*command*/) {
550   client.SendCommandResponse("OK");
551 }
552 
HandleCancelUssd(const Client & client,const std::string &)553 void CallService::HandleCancelUssd(const Client& client,
554                                    const std::string& /*command*/) {
555   client.SendCommandResponse("OK");
556 }
557 
558 /**
559  * AT+WSOS
560  *
561  * Command          Possible response(s)
562  * +WSOS=[<n>]        +CME ERROR: <err>
563  * +WSOS?             +WSOS: <n>
564  *                    +CME ERROR: <err>
565  *
566  * <n>: integer type
567  *   0 enter emergency mode
568  *   1 exit emergency mode
569  *
570  * see RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE
571  *     RIL_UNSOL_ENTER_EMERGENCY_CALLBACK_MODE
572  *     RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE in RIL
573  */
HandleEmergencyMode(const Client & client,const std::string & command)574 void CallService::HandleEmergencyMode(const Client& client,
575                                       const std::string& command) {
576   std::vector<std::string> responses;
577   CommandParser cmd(command);
578   cmd.SkipPrefix();
579 
580   if (cmd == "AT+WSOS?") {
581     std::stringstream ss;
582     ss << "+WSOS: " << in_emergency_mode_;
583     responses.push_back(ss.str());
584   } else {
585     int n = cmd.GetNextInt();
586     switch (n) {
587       case 0:  // Exit
588         in_emergency_mode_ = false;
589         break;
590       case 1:  // Enter
591         in_emergency_mode_ = true;
592         break;
593       default:
594         client.SendCommandResponse(kCmeErrorInCorrectParameters);
595         return;
596     }
597     auto nvram_config = NvramConfig::Get();
598     auto instance = nvram_config->ForInstance(service_id_);
599     instance.set_emergency_mode(in_emergency_mode_);
600     NvramConfig::SaveToFile();
601   }
602   client.SendCommandResponse("OK");
603 }
604 
CallStateUpdate()605 void CallService::CallStateUpdate() {
606   SendUnsolicitedCommand("RING");
607 }
608 
609 /**
610  * AT+REMOTECALL=<dir>,<stat>,<mode>,<mpty>,<number>,<num_type>
611  *   This command allows to dial a remote voice call with another cuttlefish
612  * emulator. If request is successful, the remote emulator can simulate hold on,
613  * hang up, reject and so on.
614  *
615  * e.g. AT+REMOTECALL=4,0,0,6521,129
616  *
617  * <stat>: integer type (state of the call)
618  *       0 active
619  *       1 held
620  *       2 dialing (MO call)
621  *       3 alerting (MO call)
622  *       4 incoming (MT call)
623  *       5 waiting (MT call)
624  * <mode>: integer type
625  *       0 voice
626  *       1 data
627  *       2 fax
628  *       3 voice followed by data, voice mode
629  *       4 alternating voice/data, voice mode
630  *       5 alternating voice/fax, voice mode
631  *       6 voice followed by data, data mode
632  *       7 alternating voice/data, data mode
633  *       8 alternating voice/fax, fax mode
634  *       9 unknown
635  * <mpty>: integer type
636  *       0 call is not one of multiparty (conference) call parties
637  *       1 call is one of multiparty (conference) call parties
638  * <number>: string here maybe remote port
639  * <num_type>: type of address octet in integer format
640  *
641  * Note: reason should be added to indicate why hang up. Since not realizing
642  *       RIL_LAST_CALL_FAIL_CAUSE, delay to be implemented.
643  */
HandleRemoteCall(const Client & client,const std::string & command)644 void CallService::HandleRemoteCall(const Client& client,
645                                    const std::string& command) {
646   CommandParser cmd(command);
647   cmd.SkipPrefix();
648 
649   int state = cmd.GetNextInt();
650   int mode = cmd.GetNextInt();
651   int mpty = cmd.GetNextInt();
652   auto number = cmd.GetNextStr();
653   int num_type = cmd.GetNextInt();
654 
655   // According to the number to determine whether it is a existing call
656   auto iter = active_calls_.begin();
657   for (; iter != active_calls_.end(); ++iter) {
658     if (iter->second.number == number) {
659       break;
660     }
661   }
662 
663   switch (state) {
664     case CallStatus::CALL_STATE_ACTIVE: {
665       if (iter != active_calls_.end()) {
666         iter->second.SetCallActive();
667         if (iter->second.timeout_serial != std::nullopt) {
668           thread_looper_->CancelSerial(*(iter->second.timeout_serial));
669         }
670       }
671       break;
672     }
673     case CallStatus::CALL_STATE_HELD:
674       if (iter != active_calls_.end()) {
675         iter->second.SetCallBackground();
676         if (iter->second.timeout_serial != std::nullopt) {
677           thread_looper_->CancelSerial(*(iter->second.timeout_serial));
678         }
679       }
680       break;
681     case CallStatus::CALL_STATE_HANGUP:
682       if (iter != active_calls_.end()) {
683         auto client = iter->second.remote_client;
684         if (client != std::nullopt) {
685           CloseRemoteConnection(*client);
686         }
687         if (iter->second.timeout_serial != std::nullopt) {
688           thread_looper_->CancelSerial(*(iter->second.timeout_serial));
689         }
690         active_calls_.erase(iter);
691       }
692       break;
693     case CallStatus::CALL_STATE_INCOMING: {
694       if (network_service_) {
695         if (network_service_->isRadioOff()) {
696           LOG(DEBUG) << " radio is off, reject incoming call from: " << number;
697           network_service_->CloseRemoteConnection(client.Id());
698           return;
699         }
700       }
701       CallStatus call_status(number);
702       call_status.is_remote_call = true;
703       call_status.is_voice_mode = mode;
704       call_status.is_multi_party = mpty;
705       call_status.is_mobile_terminated = true;
706       call_status.is_international = (num_type == 145);
707       call_status.remote_client = client.Id();
708       call_status.call_state = CallStatus::CALL_STATE_INCOMING;
709 
710       auto index = FindFreeCallIndex();
711       active_calls_[index] = call_status;
712       break;
713     }
714     default:  // Unsupported call state
715       return;
716   }
717   thread_looper_->Post(makeSafeCallback(this, &CallService::CallStateUpdate));
718 }
719 
720 }  // namespace cuttlefish
721