void tst_QSimToolkit::testDeliverEventDownload() { QFETCH( QByteArray, data ); QFETCH( QByteArray, payload ); QFETCH( int, event ); QFETCH( int, sourceDevice ); // Output a dummy line to give some indication of which test we are currently running. qDebug() << ""; // Clear the client/server state. server->clear(); deliveredCommand = QSimCommand(); // Compose and send the envelope. QSimEnvelope env; env.setType( QSimEnvelope::EventDownload ); env.setSourceDevice( (QSimCommand::Device)sourceDevice ); env.setEvent( (QSimEnvelope::Event)event ); env.setExtensionData( payload ); client->sendEnvelope( env ); // Wait for the envelope to be received. QVERIFY( QFutureSignal::wait( server, SIGNAL(envelopeSeen()), 100 ) ); // Check that the envelope is what we expected to get and that we didn't // get any terminal responses yet. QCOMPARE( server->responseCount(), 0 ); QCOMPARE( server->envelopeCount(), 1 ); QByteArray lastenv = server->lastEnvelope(); lastenv[2] = data[2]; // Handle 0x19 vs 0x99 discrepancy. QCOMPARE( lastenv, data ); }
void SimApp::keyPressEvent(QKeyEvent *ke) { if (ke->key() == Qt::Key_Context1) { if (view) { if (view->command().hasHelp()) { // help requested if (view->command().type() == QSimCommand::SetupMenu) { QSimEnvelope env; env.setType(QSimEnvelope::MenuSelection); env.setSourceDevice(QSimCommand::Keypad); env.setMenuItem(view->helpIdentifier()); env.setRequestHelp(true); sendEnvelope( env ); } else { QSimTerminalResponse resp; resp.setCommand(view->command()); resp.setResult(QSimTerminalResponse::HelpInformationRequested); resp.setMenuItem(view->helpIdentifier()); sendResponse( resp ); } } } } QMainWindow::keyPressEvent(ke); }
/*! Sends an \c{ENVELOPE} \a env to the SIM toolkit application. This is typically used for selecting items from the main menu. The implementation in QModemSimToolkit sends the envelope to the SIM using the \c{AT+CSIM} command. This will need to be overridden by the modem vendor plugin if the modem uses some other mechanism for sending envelopes to the SIM. \sa sendResponse(), command() */ void QModemSimToolkit::sendEnvelope( const QSimEnvelope& env ) { QByteArray cmd; QByteArray pdu = env.toPdu(); cmd += (char)0xA0; cmd += (char)0xC2; cmd += (char)0x00; cmd += (char)0x00; cmd += (char)pdu.size(); cmd += pdu; service()->chat( "AT+CSIM=" + QString::number( cmd.size() * 2 ) + "," + QAtUtils::toHex( cmd ) ); }
void tst_QSimToolkit::testEncodeEventDownload() { QFETCH( QByteArray, data ); QFETCH( QByteArray, payload ); QFETCH( int, event ); QFETCH( int, sourceDevice ); // Output a dummy line to give some indication of which test we are currently running. qDebug() << ""; // Check that the envelope PDU can be parsed correctly. QSimEnvelope decodedEnv = QSimEnvelope::fromPdu(data); QVERIFY( decodedEnv.type() == QSimEnvelope::EventDownload ); QVERIFY( decodedEnv.sourceDevice() == (QSimCommand::Device)sourceDevice ); QCOMPARE( (int)decodedEnv.event(), event ); QCOMPARE( decodedEnv.extensionData(), payload ); // Check that the original envelope PDU can be reconstructed correctly. QByteArray pdu = decodedEnv.toPdu(); pdu[2] = data[2]; // Handle 0x19 vs 0x99 discrepancy. QCOMPARE( pdu, data ); }
bool SimApplication::execute( const QString& cmd ) { // Process SIM toolkit begin and end commands by forcing the app back to the main menu. if ( cmd == "AT*TSTB" || cmd == "AT*TSTE") { d->rules->respond( "OK" ); abort(); return true; } // If not AT+CSIM, then this is not a SIM toolkit command. if ( !cmd.startsWith( "AT+CSIM=" ) ) return false; // Extract the binary payload of the AT+CSIM command. int comma = cmd.indexOf( QChar(',') ); if ( comma < 0 ) return false; QByteArray param = QAtUtils::fromHex( cmd.mid(comma + 1) ); if ( param.length() < 5 || param[0] != (char)0xA0 ) return false; // Check for TERMINAL PROFILE, FETCH, TERMINAL RESPONSE, // and ENVELOPE packets. if ( param[1] == (char)0x10 ) { // Download of a TERMINAL PROFILE. We respond with a simple OK, // on the assumption that what we were sent was valid. d->rules->respond( "+CSIM: 4,9000\nOK" ); // Abort the SIM application and force it to return to the main menu. abort(); } else if ( param[1] == (char)0x12 ) { // Fetch the current command contents. QByteArray resp = d->currentCommand; if ( resp.isEmpty() ) { // We weren't expecting a FETCH. d->rules->respond( "+CSIM: 4,6F00\nOK" ); return true; } resp += (char)0x90; resp += (char)0x00; d->rules->respond( "+CSIM: " + QString::number( resp.size() * 2 ) + "," + QAtUtils::toHex( resp ) + "\nOK" ); } else if ( param[1] == (char)0x14 ) { // Process a TERMINAL RESPONSE message. QSimTerminalResponse resp; resp = QSimTerminalResponse::fromPdu( param.mid(5) ); if ( resp.command().type() != QSimCommand::NoCommand && resp.command().type() != d->expectedType ) { // Response to the wrong type of command. d->rules->respond( "+CSIM: 4,6F00\nOK" ); return true; } response( resp ); } else if ( param[1] == (char)0xC2 ) { // Process a menu selection ENVELOPE message. We turn it into a // QSimTerminalResponse to make it easier to process. QSimEnvelope env; env = QSimEnvelope::fromPdu( param.mid(5) ); if ( env.type() == QSimEnvelope::EventDownload ) { d->rules->respond( "+CSIM: 4,9000\nOK" ); return true; } if ( env.type() != QSimEnvelope::MenuSelection ) return false; if ( d->expectedType != QSimCommand::SetupMenu ) { // Envelope sent for the wrong type of command. d->rules->respond( "+CSIM: 4,6F00\nOK" ); return true; } d->rules->respond( "+CSIM: 4,9000\nOK" ); d->expectedType = QSimCommand::NoCommand; d->currentCommand = QByteArray(); d->target = 0; d->slot = 0; if ( env.requestHelp() ) mainMenuHelpRequest( env.menuItem() ); else mainMenuSelection( env.menuItem() ); } else { // This SIM command is not related to SIM toolkit - ignore it. return false; } return true; }
/*! Returns an envelope object corresponding to the data in \a pdu. The data is decoded as described in 3GPP TS 11.14. \sa toPdu() */ QSimEnvelope QSimEnvelope::fromPdu( const QByteArray& pdu ) { QSimEnvelope env; QByteArray content; uint posn = 0; uint newPosn; uint tag, length; readBer( pdu, posn, tag, length ); if ( ( tag & 0xF0 ) != 0xD0 ) { // Doesn't appear to be a valid ENVELOPE. return env; } env.setType( (QSimEnvelope::Type)tag ); content = pdu.mid( posn, length ); posn = 0; readBer( content, posn, tag, length ); for (;;) { if ( ( posn + length ) > (uint)content.size() ) break; newPosn = posn + length; switch ( tag & 0x7F ) { case 0x02: { // Device identities, GSM 11.14, section 12.7. if ( length >= 2 ) { env.setSourceDevice ( (QSimCommand::Device)( content[posn] & 0xFF ) ); env.setDestinationDevice ( (QSimCommand::Device)( content[posn + 1] & 0xFF ) ); } } break; case 0x10: { // Menu item identifier, GSM 11.14, section 12.10. if ( length > 0 ) env.setMenuItem( (uint)(content[posn] & 0xFF) ); } break; case 0x15: { // Help requested, GSM 11.14, section 12.21. env.setRequestHelp( true ); } break; case 0x19: { // Event list, GSM 11.14, section 12.25. if ( length > 0 ) env.setEvent( (QSimEnvelope::Event)( content[posn] & 0xFF ) ); } break; default: { // Don't know what this is, so add it as an extension field. env.addExtensionField( tag, content.mid( posn, length ) ); } break; } posn = newPosn; if ( posn >= (uint)content.size() ) break; readBer( content, posn, tag, length ); } return env; }
void NeoSimToolkit::sendEnvelope( const QSimEnvelope& env ) { service()->primaryAtChat()->chat ( "AT%SATE=\"" + QAtUtils::toHex( env.toPdu() ) + "\"" ); }