ESP8266-based WiFi serial modem emulator ROM
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

AT Handling: Add ATQ and ATE, do proper outputting based on those

With echo enabled, only print \r after accepting a command, and once
the command wants to start output, it should print the \n. With ATQ
set (quiet mode), that \n is not printed since the OK or ERROR is
not printed.

Also loop through all command input so chained command sequences
like "ATEQ1" will be parsed as "ATE0" and "ATQ1".

+258 -122
+3
util.cpp
··· 44 44 sizeof(settings->magic)); 45 45 settings->revision = EEPROM_REVISION; 46 46 47 + settings->echo = 1; 48 + settings->quiet = 0; 49 + 47 50 /* a slow default for old computers */ 48 51 settings->baud = 300; 49 52
+2
wifippp.h
··· 51 51 uint8_t reg_i; 52 52 #define REG_I_XONXOFF_OFF 0 53 53 #define REG_I_XONXOFF_ON 1 54 + uint8_t echo; 55 + uint8_t quiet; 54 56 }; 55 57 56 58 enum {
+253 -122
wifippp.ino
··· 25 25 static unsigned int lastcmdlen = 0; 26 26 static int plusses = 0; 27 27 static unsigned long plus_wait = 0; 28 + static bool dtr = false; 28 29 29 30 void 30 31 loop(void) ··· 55 56 if (curcmdlen == 0 && (b != 'A' && b != 'a')) { 56 57 return; 57 58 } else if (curcmdlen == 1 && b == '/') { 58 - output("/\r\n"); 59 + if (settings->echo) 60 + output("/\r"); 59 61 curcmd[0] = '\0'; 60 62 curcmdlen = 0; 61 63 exec_cmd((char *)&lastcmd, lastcmdlen); 62 64 break; 63 65 } else if (curcmdlen == 1 && (b != 'T' && b != 't')) { 64 - output("\b \b"); 66 + if (settings->echo) 67 + output("\b \b"); 65 68 curcmdlen = 0; 66 69 return; 67 70 } ··· 86 89 } 87 90 } 88 91 } 89 - output("\r\n"); 92 + output("\r"); 90 93 curcmd[curcmdlen] = '\0'; 91 94 exec_cmd((char *)&curcmd, curcmdlen); 92 95 curcmd[0] = '\0'; ··· 95 98 case '\b': 96 99 case 127: 97 100 if (curcmdlen) { 98 - output("\b \b"); 101 + if (settings->echo) 102 + output("\b \b"); 99 103 curcmdlen--; 100 104 } 101 105 break; 102 106 default: 103 107 curcmd[curcmdlen++] = b; 104 - output(b); 108 + if (settings->echo) 109 + output(b); 105 110 } 106 111 break; 107 112 case STATE_TELNET: ··· 114 119 /* received no input within 500ms of a plus */ 115 120 if (plusses >= 3) { 116 121 state = STATE_AT; 117 - output("\r\nOK\r\n"); 122 + if (!settings->quiet) 123 + outputf("\nOK\r\n"); 118 124 } else { 119 125 /* cancel, flush any plus signs received */ 120 126 for (i = 0; i < plusses; i++) ··· 144 150 serial_write(b); 145 151 return; 146 152 } else if (!telnet_connected()) { 147 - output("\r\nNO CARRIER\r\n"); 153 + if (!settings->quiet) 154 + output("\r\nNO CARRIER\r\n"); 148 155 state = STATE_AT; 149 156 break; 150 157 } ··· 159 166 exec_cmd(char *cmd, size_t len) 160 167 { 161 168 char *errstr = NULL; 169 + char *lcmd, *olcmd; 170 + char cmd_char; 171 + uint8_t cmd_num = 0; 172 + bool did_nl = false; 162 173 163 - char *lcmd = (char *)malloc(len + 1); 174 + lcmd = olcmd = (char *)malloc(len + 1); 164 175 if (lcmd == NULL) { 165 176 outputf("ERROR malloc %zu failed\r\n", len); 166 177 return; ··· 170 181 lcmd[i] = tolower(cmd[i]); 171 182 lcmd[len] = '\0'; 172 183 184 + /* shouldn't be able to get here, but just in case */ 173 185 if (len < 2 || lcmd[0] != 'a' || lcmd[1] != 't') { 174 186 errstr = strdup("not an AT command"); 175 187 goto error; ··· 178 190 memcpy(&lastcmd, lcmd, len + 1); 179 191 lastcmdlen = len; 180 192 181 - if (len == 2) { 182 - output("OK\r\n"); 183 - return; 193 + /* strip AT */ 194 + cmd += 2; 195 + lcmd += 2; 196 + len -= 2; 197 + 198 + /* whether we printed a newline in our response */ 199 + did_nl = false; 200 + 201 + parse_cmd: 202 + if (lcmd[0] == '\0') 203 + goto done_parsing; 204 + 205 + /* remove command character */ 206 + cmd_char = lcmd[0]; 207 + len--; 208 + cmd++; 209 + lcmd++; 210 + 211 + /* find optional single digit after command, defaulting to 0 */ 212 + cmd_num = 0; 213 + if (cmd[0] >= '0' && cmd[0] <= '9') { 214 + if (cmd[1] >= '0' && cmd[1] <= '9') 215 + /* nothing uses more than 1 digit */ 216 + goto error; 217 + cmd_num = cmd[0] - '0'; 218 + len--; 219 + cmd++; 220 + lcmd++; 184 221 } 185 222 186 - switch (lcmd[2]) { 223 + switch (cmd_char) { 187 224 case 'd': { 188 225 char *host, *ohost, *bookmark; 189 226 uint16_t port; 190 227 int chars; 191 228 int index; 192 229 193 - if (len < 5) 230 + if (len < 2) 194 231 goto error; 195 232 196 - switch (lcmd[3]) { 233 + switch (lcmd[0]) { 197 234 case 't': 198 235 /* ATDT: dial a host */ 199 236 host = ohost = (char *)malloc(len); 200 237 if (host == NULL) 201 238 goto error; 202 239 host[0] = '\0'; 203 - if (sscanf(lcmd, "atdt%[^:]:%hu%n", host, &port, 240 + if (sscanf(lcmd, "t%[^:]:%hu%n", host, &port, 204 241 &chars) == 2 && chars > 0) 205 242 /* matched host:port */ 206 243 ; 207 - else if (sscanf(lcmd, "atdt%[^:]%n", host, &chars) == 1 244 + else if (sscanf(lcmd, "t%[^:]%n", host, &chars) == 1 208 245 && chars > 0) 209 246 /* host without port */ 210 247 port = 23; ··· 215 252 break; 216 253 case 's': 217 254 /* ATDS: dial a stored host */ 218 - if (sscanf(lcmd, "atds%d", &index) != 1) 255 + if (sscanf(lcmd, "s%d", &index) != 1) 219 256 goto error; 220 257 221 258 if (index < 1 || index > NUM_BOOKMARKS) { ··· 257 294 goto error; 258 295 } 259 296 297 + /* no commands can follow */ 298 + len = 0; 299 + 260 300 if (strcasecmp(host, "ppp") == 0) { 261 301 ip4_addr_t t_addr; 262 302 ip_addr_copy(t_addr, settings->ppp_server_ip); 263 - outputf("DIALING %s:PPP\r\n", ipaddr_ntoa(&t_addr)); 303 + if (!settings->quiet) 304 + outputf("\nDIALING %s:PPP\r\n", 305 + ipaddr_ntoa(&t_addr)); 264 306 265 307 telnet_disconnect(); 266 - if (ppp_start()) { 308 + if (ppp_start()) 267 309 /* ppp_start outputs CONNECT line, since it has 268 310 * to do so before calling ppp_listen */ 269 311 state = STATE_PPP; 270 - } else { 312 + else if (!settings->quiet) 271 313 output("NO ANSWER\r\n"); 272 - } 273 314 } else { 274 - outputf("DIALING %s:%d\r\n", host, port); 315 + if (!settings->quiet) 316 + outputf("\nDIALING %s:%d\r\n", host, port); 275 317 276 318 if (telnet_connect(host, port) == 0) { 277 - outputf("CONNECT %d %s:%d\r\n", settings->baud, 278 - host, port); 319 + if (!settings->quiet) 320 + outputf("CONNECT %d %s:%d\r\n", 321 + settings->baud, host, port); 279 322 state = STATE_TELNET; 280 - } else 281 - output("NO ANSWER\r\n"); 323 + } else if (!settings->quiet) 324 + output("\nNO ANSWER\r\n"); 282 325 } 283 326 284 - free(ohost); 327 + if (!settings->quiet) 328 + did_nl = true; 285 329 330 + free(ohost); 286 331 break; 287 332 } 333 + case 'e': 334 + /* ATE/ATE0 or ATE1: disable or enable echo */ 335 + switch (cmd_num) { 336 + case 0: 337 + settings->echo = 0; 338 + break; 339 + case 1: 340 + settings->echo = 1; 341 + break; 342 + default: 343 + goto error; 344 + } 345 + break; 288 346 case 'h': 289 - telnet_disconnect(); 290 - output("OK\r\n"); 347 + /* ATH/ATH0: hangup */ 348 + switch (cmd_num) { 349 + case 0: 350 + telnet_disconnect(); 351 + break; 352 + default: 353 + goto error; 354 + } 291 355 break; 292 356 case 'i': 293 - if (len > 4) 294 - goto error; 357 + /* ATI/ATI#: show information pages */ 358 + switch (cmd_num) { 359 + case 0: { 360 + /* ATI/ATI0: show settings */ 361 + ip4_addr_t t_addr; 295 362 296 - switch (len == 3 ? '0' : cmd[3]) { 297 - case '0': { 298 - /* ATI or ATI0: show settings */ 299 - ip4_addr_t t_addr; 363 + output("\n"); 300 364 301 365 outputf("Firmware version: %s\r\n", 302 366 WIFISTATION_VERSION); 303 367 304 - outputf("Serial baud rate: %d\r\n", 305 - settings->baud); 368 + outputf("Default baud rate: %d\r\n", settings->baud); 369 + outputf("Current baud rate: %d\r\n", 370 + Serial.baudRate()); 306 371 307 372 outputf("Default WiFi SSID: %s\r\n", 308 373 settings->wifi_ssid); ··· 334 399 i + 1, settings->bookmarks[i]); 335 400 } 336 401 337 - output("OK\r\n"); 402 + did_nl = true; 338 403 break; 339 404 } 340 - case '1': { 405 + case 1: { 341 406 /* ATI1: scan for wifi networks */ 342 407 int n = WiFi.scanNetworks(); 408 + 409 + output("\n"); 343 410 344 411 for (int i = 0; i < n; i++) { 345 412 outputf("%02d: %s (chan %d, %ddBm, ", ··· 371 438 372 439 output(")\r\n"); 373 440 } 374 - output("OK\r\n"); 441 + did_nl = true; 375 442 break; 376 443 } 377 - case '3': 444 + case 3: 378 445 /* ATI3: show version */ 379 - outputf("%s\r\nOK\r\n", WIFISTATION_VERSION); 446 + outputf("\n%s\r\n", WIFISTATION_VERSION); 447 + did_nl = true; 380 448 break; 381 449 default: 382 450 goto error; 383 451 } 384 452 break; 385 453 case 'o': 386 - if (telnet_connected()) 387 - state = STATE_TELNET; 388 - else 454 + /* ATO: go back online after a +++ */ 455 + switch (cmd_num) { 456 + case 0: 457 + if (telnet_connected()) 458 + state = STATE_TELNET; 459 + else 460 + goto error; 461 + break; 462 + default: 463 + goto error; 464 + } 465 + break; 466 + case 'q': 467 + /* ATQ/ATQ0 or ATQ1: disable or enable quiet */ 468 + switch (cmd_num) { 469 + case 0: 470 + settings->quiet = 0; 471 + break; 472 + case 1: 473 + settings->quiet = 1; 474 + break; 475 + default: 389 476 goto error; 477 + } 390 478 break; 391 479 case 'z': 392 - output("OK\r\n"); 393 - ESP.restart(); 480 + /* ATZ/ATZ0: restart */ 481 + switch (cmd_num) { 482 + case 0: 483 + if (!settings->quiet) 484 + output("\nOK\r\n"); 485 + ESP.restart(); 486 + /* NOTREACHED */ 487 + default: 488 + goto error; 489 + } 394 490 break; 395 491 case '$': 396 - /* wifi232 commands */ 397 - 398 - if (strcmp(lcmd, "at$net=0") == 0) { 492 + /* wifi232 commands, all consume the rest of the input string */ 493 + if (strcmp(lcmd, "net=0") == 0) { 399 494 /* AT$NET=0: disable telnet setting */ 400 495 settings->telnet = 0; 401 - output("OK\r\n"); 402 - } else if (strcmp(lcmd, "at$net=1") == 0) { 496 + } else if (strcmp(lcmd, "net=1") == 0) { 403 497 /* AT$NET=1: enable telnet setting */ 404 498 settings->telnet = 1; 405 - output("OK\r\n"); 406 - } else if (strcmp(lcmd, "at$net?") == 0) { 499 + } else if (strcmp(lcmd, "net?") == 0) { 407 500 /* AT$NET?: show telnet setting */ 408 - outputf("%d\r\nOK\r\n", settings->telnet); 409 - } else if (strncmp(lcmd, "at$pass=", 8) == 0) { 501 + outputf("\n%d\r\n", settings->telnet); 502 + did_nl = true; 503 + } else if (strncmp(lcmd, "pass=", 8) == 0) { 410 504 /* AT$PASS=...: store wep/wpa passphrase */ 411 505 memset(settings->wifi_pass, 0, 412 506 sizeof(settings->wifi_pass)); 413 - strncpy(settings->wifi_pass, cmd + 8, 507 + strncpy(settings->wifi_pass, cmd + 5, 414 508 sizeof(settings->wifi_pass)); 415 - output("OK\r\n"); 416 509 417 510 WiFi.disconnect(); 418 511 if (settings->wifi_ssid[0]) 419 512 WiFi.begin(settings->wifi_ssid, 420 513 settings->wifi_pass); 421 - } else if (strcmp(lcmd, "at$pass?") == 0) { 514 + } else if (strcmp(lcmd, "pass?") == 0) { 422 515 /* AT$PASS?: print wep/wpa passphrase */ 423 - outputf("%s\r\nOK\r\n", settings->wifi_pass); 424 - } else if (strncmp(lcmd, "at$pppc=", 8) == 0) { 516 + outputf("\n%s\r\n", settings->wifi_pass); 517 + did_nl = true; 518 + } else if (strncmp(lcmd, "pppc=", 5) == 0) { 425 519 /* AT$PPPC=...: store PPP client IP */ 426 520 ip4_addr_t t_addr; 427 521 428 - if (!ipaddr_aton(cmd + 8, &t_addr)) { 522 + if (!ipaddr_aton(cmd + 5, &t_addr)) { 429 523 errstr = strdup("invalid IP"); 430 524 goto error; 431 525 } 432 526 433 527 ip_addr_copy(settings->ppp_client_ip, t_addr); 434 - output("OK\r\n"); 435 - } else if (strcmp(lcmd, "at$pppc?") == 0) { 528 + } else if (strcmp(lcmd, "pppc?") == 0) { 436 529 /* AT$PPPC?: print PPP client IP */ 437 530 ip4_addr_t t_addr; 438 531 ip_addr_copy(t_addr, settings->ppp_client_ip); 439 - outputf("%s\r\nOK\r\n", ipaddr_ntoa(&t_addr)); 440 - } else if (strncmp(lcmd, "at$ppps=", 8) == 0) { 532 + outputf("\n%s\r\n", ipaddr_ntoa(&t_addr)); 533 + did_nl = true; 534 + } else if (strncmp(lcmd, "ppps=", 5) == 0) { 441 535 /* AT$PPPS=...: store PPP server IP */ 442 536 ip4_addr_t t_addr; 443 537 444 - if (!ipaddr_aton(cmd + 8, &t_addr)) { 538 + if (!ipaddr_aton(cmd + 5, &t_addr)) { 445 539 errstr = strdup("invalid IP"); 446 540 goto error; 447 541 } 448 542 449 543 ip_addr_copy(settings->ppp_server_ip, t_addr); 450 - output("OK\r\n"); 451 544 /* re-bind to the new ip */ 452 545 socks_setup(); 453 - } else if (strcmp(lcmd, "at$ppps?") == 0) { 546 + } else if (strcmp(lcmd, "ppps?") == 0) { 454 547 /* AT$PPPS?: print PPP server IP */ 455 548 ip4_addr_t t_addr; 456 549 ip_addr_copy(t_addr, settings->ppp_server_ip); 457 - outputf("%s\r\nOK\r\n", ipaddr_ntoa(&t_addr)); 458 - } else if (strncmp(lcmd, "at$sb=", 6) == 0) { 550 + outputf("\n%s\r\n", ipaddr_ntoa(&t_addr)); 551 + did_nl = true; 552 + } else if (strncmp(lcmd, "sb=", 3) == 0) { 459 553 uint32_t baud = 0; 460 554 int chars = 0; 461 555 462 556 /* AT$SB=...: set baud rate */ 463 - if (sscanf(lcmd, "at$sb=%d%n", &baud, &chars) != 1 || 557 + if (sscanf(lcmd, "sb=%d%n", &baud, &chars) != 1 || 464 558 chars == 0) { 465 559 output("ERROR invalid baud rate\r\n"); 466 560 break; ··· 478 572 case 57600: 479 573 case 115200: 480 574 settings->baud = baud; 481 - outputf("OK switching to %d\r\n", 482 - settings->baud); 575 + if (!settings->quiet) 576 + outputf("\nOK switching to %d\r\n", 577 + settings->baud); 483 578 serial_flush(); 484 579 serial_begin(settings->baud); 485 580 break; ··· 487 582 output("ERROR unsupported baud rate\r\n"); 488 583 break; 489 584 } 490 - } else if (strcmp(lcmd, "at$sb?") == 0) { 585 + } else if (strcmp(lcmd, "sb?") == 0) { 491 586 /* AT$SB?: print baud rate */ 492 - outputf("%d\r\nOK\r\n", settings->baud); 493 - } else if (strncmp(lcmd, "at$ssid=", 8) == 0) { 587 + outputf("\n%d\r\n", settings->baud); 588 + did_nl = true; 589 + } else if (strncmp(lcmd, "ssid=", 5) == 0) { 494 590 /* AT$SSID=...: set wifi ssid */ 495 591 memset(settings->wifi_ssid, 0, 496 592 sizeof(settings->wifi_ssid)); 497 - strncpy(settings->wifi_ssid, cmd + 8, 593 + strncpy(settings->wifi_ssid, cmd + 5, 498 594 sizeof(settings->wifi_ssid)); 499 - output("OK\r\n"); 500 595 501 596 WiFi.disconnect(); 502 597 if (settings->wifi_ssid[0]) 503 598 WiFi.begin(settings->wifi_ssid, 504 599 settings->wifi_pass); 505 - } else if (strcmp(lcmd, "at$ssid?") == 0) { 600 + } else if (strcmp(lcmd, "ssid?") == 0) { 506 601 /* AT$SSID?: print wifi ssid */ 507 - outputf("%s\r\nOK\r\n", settings->wifi_ssid); 508 - } else if (strncmp(lcmd, "at$syslog=", 10) == 0) { 602 + outputf("\n%s\r\n", settings->wifi_ssid); 603 + did_nl = true; 604 + } else if (strncmp(lcmd, "syslog=", 7) == 0) { 509 605 /* AT$SYSLOG=...: set syslog server */ 510 606 memset(settings->syslog_server, 0, 511 607 sizeof(settings->syslog_server)); 512 - strncpy(settings->syslog_server, cmd + 10, 608 + strncpy(settings->syslog_server, cmd + 7, 513 609 sizeof(settings->syslog_server)); 514 - output("OK\r\n"); 515 610 syslog_setup(); 516 611 syslog.logf(LOG_INFO, "syslog server changed to %s", 517 612 settings->syslog_server); 518 - } else if (strcmp(lcmd, "at$syslog?") == 0) { 613 + } else if (strcmp(lcmd, "syslog?") == 0) { 519 614 /* AT$SYSLOG?: print syslog server */ 520 - outputf("%s\r\nOK\r\n", settings->syslog_server); 521 - } else if (strncmp(lcmd, "at$tts=", 7) == 0) { 615 + outputf("\n%s\r\n", settings->syslog_server); 616 + did_nl = true; 617 + } else if (strncmp(lcmd, "tts=", 4) == 0) { 522 618 /* AT$TTS=: set telnet NAWS */ 523 619 int w, h, chars; 524 - if (sscanf(lcmd + 7, "%dx%d%n", &w, &h, &chars) == 2 && 620 + if (sscanf(lcmd + 4, "%dx%d%n", &w, &h, &chars) == 2 && 525 621 chars > 0) { 526 622 if (w < 1 || w > 255) { 527 623 errstr = strdup("invalid width"); ··· 534 630 535 631 settings->telnet_tts_w = w; 536 632 settings->telnet_tts_h = h; 537 - output("OK\r\n"); 538 633 } else { 539 634 errstr = strdup("must be WxH"); 540 635 goto error; 541 636 } 542 - } else if (strcmp(lcmd, "at$tts?") == 0) { 637 + } else if (strcmp(lcmd, "tts?") == 0) { 543 638 /* AT$TTS?: show telnet NAWS setting */ 544 - outputf("%dx%d\r\nOK\r\n", settings->telnet_tts_w, 639 + outputf("\n%dx%d\r\n", settings->telnet_tts_w, 545 640 settings->telnet_tts_h); 546 - } else if (strncmp(lcmd, "at$tty=", 7) == 0) { 641 + did_nl = true; 642 + } else if (strncmp(lcmd, "tty=", 4) == 0) { 547 643 /* AT$TTY=: set telnet TTYPE */ 548 644 memset(settings->telnet_tterm, 0, 549 645 sizeof(settings->telnet_tterm)); 550 - strncpy(settings->telnet_tterm, cmd + 7, 646 + strncpy(settings->telnet_tterm, cmd + 4, 551 647 sizeof(settings->telnet_tterm)); 552 - output("OK\r\n"); 553 - } else if (strcmp(lcmd, "at$tty?") == 0) { 648 + } else if (strcmp(lcmd, "tty?") == 0) { 554 649 /* AT$TTY?: show telnet TTYPE setting */ 555 - outputf("%s\r\nOK\r\n", settings->telnet_tterm); 556 - } else if (strcmp(lcmd, "at$update?") == 0) { 650 + outputf("\n%s\r\n", settings->telnet_tterm); 651 + did_nl = true; 652 + } else if (strcmp(lcmd, "update?") == 0) { 557 653 /* AT$UPDATE?: show whether an OTA update is available */ 558 654 update_process(false, false); 559 - } else if (strcmp(lcmd, "at$update!") == 0) { 655 + } else if (strcmp(lcmd, "update!") == 0) { 560 656 /* AT$UPDATE!: force an OTA update */ 561 657 update_process(true, true); 562 - } else if (strcmp(lcmd, "at$update") == 0) { 658 + } else if (strcmp(lcmd, "update") == 0) { 563 659 /* AT$UPDATE: do an OTA update */ 564 660 update_process(true, false); 565 661 } else 566 662 goto error; 663 + 664 + /* consume all chars */ 665 + len = 0; 567 666 break; 568 667 case '&': 569 - if (len < 4) 668 + if (cmd[0] == '\0') 570 669 goto error; 571 670 572 - switch (lcmd[3]) { 573 - case 'w': 574 - /* AT&W: save settings */ 575 - if (len != 4) 671 + cmd_char = lcmd[0]; 672 + len--; 673 + cmd++; 674 + lcmd++; 675 + 676 + /* find optional single digit after &command, defaulting to 0 */ 677 + cmd_num = 0; 678 + if (cmd[0] >= '0' && cmd[0] <= '9') { 679 + if (cmd[1] >= '0' && cmd[1] <= '9') 680 + /* nothing uses more than 1 digit */ 576 681 goto error; 682 + cmd_num = cmd[0] - '0'; 683 + len--; 684 + cmd++; 685 + lcmd++; 686 + } 577 687 578 - if (!EEPROM.commit()) 688 + switch (cmd_char) { 689 + case 'w': 690 + switch (cmd_num) { 691 + case 0: 692 + /* AT&W: save settings */ 693 + if (!EEPROM.commit()) 694 + goto error; 695 + break; 696 + default: 579 697 goto error; 580 - 581 - output("OK\r\n"); 698 + } 582 699 break; 583 700 case 'z': { 584 701 /* AT&Z: manage bookmarks */ ··· 586 703 uint8_t query; 587 704 int chars = 0; 588 705 589 - if (sscanf(lcmd, "at&z%u=%n", &index, &chars) == 1 && 706 + if (sscanf(lcmd, "%u=%n", &index, &chars) == 1 && 590 707 chars > 0) { 591 708 /* AT&Zn=...: store address */ 592 709 query = 0; 593 - } else if (sscanf(lcmd, "at&z%u?%n", &index, 594 - &chars) == 1 && chars > 0) { 710 + } else if (sscanf(lcmd, "%u?%n", &index, &chars) == 1 && 711 + chars > 0) { 595 712 /* AT&Zn?: query stored address */ 596 713 query = 1; 597 714 } else { ··· 605 722 } 606 723 607 724 if (query) { 608 - outputf("%s\r\nOK\r\n", 725 + outputf("\n%s\r\n", 609 726 settings->bookmarks[index - 1]); 727 + did_nl = true; 610 728 } else { 611 729 memset(settings->bookmarks[index - 1], 0, 612 730 sizeof(settings->bookmarks[0])); 613 731 strncpy(settings->bookmarks[index - 1], 614 - cmd + 6, 732 + cmd + 2, 615 733 sizeof(settings->bookmarks[0]) - 1); 616 - output("OK\r\n"); 617 734 } 735 + 736 + /* consume all chars */ 737 + len = 0; 618 738 break; 619 739 } 620 740 default: ··· 625 745 goto error; 626 746 } 627 747 628 - if (lcmd) 629 - free(lcmd); 748 + done_parsing: 749 + /* if any len left, parse as another command */ 750 + if (len > 0) 751 + goto parse_cmd; 752 + 753 + if (olcmd) 754 + free(olcmd); 755 + 756 + if (!settings->quiet) 757 + outputf("%sOK\r\n", did_nl ? "" : "\n"); 758 + 630 759 return; 631 760 632 761 error: 633 - if (lcmd) 634 - free(lcmd); 762 + if (olcmd) 763 + free(olcmd); 635 764 636 - output("ERROR"); 637 - if (errstr != NULL) { 638 - outputf(" %s", errstr); 639 - free(errstr); 765 + if (!settings->quiet) { 766 + output("\nERROR"); 767 + if (errstr != NULL) { 768 + outputf(" %s", errstr); 769 + free(errstr); 770 + } 771 + output("\r\n"); 640 772 } 641 - output("\r\n"); 642 773 }