> A clean way to do this is with events. The Arduino doesn’t work that way, as you continuously have to ask “is this button pressed?” many thousand times a second, but one can rather easily fake an event-driven architecture on top of this with some code.
That's pretty good, but it can only handle two interrupts, and you can't delay in the function. I suspect it might have messed with the shield somehow, and it wasn't really necessary for the rotary dialer because the phone isn't doing anything else while waiting for the pulses.
Instead of delaying in code, think about having the main loop enter the execution routines of a few FSMs (modem FSM, i/o FSM, etc). In this model, a FSM state function can just return early if it's waiting for an even, giving execution time to other FSMs.
Of course, a better approach would be to run a RTOS on your uC, like the venerable FreeRTOS. Then you can just run tasks that can sleep, communicate via queues, and you can even get preemption if you wish. But I'm not sure it's available for the Arduino.
Additionally, since you're using a SIM90x, why are you polling the modem? Out-of-band events (incoming call, new text message) usually arrive in the form of Unsolicited Messages, like +CMTI for a new SMS or RING for an incoming call. You can interrupt on each character received via UART, and do your processing there.
That's how it works now (the FSM), which is why an interrupt isn't really necessary (the rotary dial state doesn't do anything other than poll for the dialing). Also, it's a bit overkill to load a RTOS for the 50 lines of code this thing has.
The polling of the shield is done because that's the way the shield library works, and I didn't want to rewrite the entire thing when it works fine as it is now, really...
http://www.arduino.cc/en/Reference/AttachInterrupt