Fixed issue where the LRC of a card was the reverse of the start
[magread] / magread.cpp
1 /*
2     This file is part of MagRead.
3
4     MagRead is free software: you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation, either version 3 of the License, or
7     (at your option) any later version.
8
9     MagRead is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with MagRead.  If not, see <http://www.gnu.org/licenses/>.
16     
17     Written by Jeffrey Malone <ieatlint@tehinterweb.com>
18     http://blog.tehinterweb.com
19 */
20 #include "magread.h"
21
22 #include <QDebug>
23
24 MagRead::MagRead(QWidget *parent) : QMainWindow(parent) {
25         mainPage();
26
27         captureAudio = false;
28         partialRead = false;
29
30         qRegisterMetaType<MagCard>( "MagCard" );
31
32         connect( &audioInput, SIGNAL( cardRead( const MagCard& ) ), this, SLOT( cardRead( const MagCard& ) ) );
33         connect( &audioInput, SIGNAL( error( const QString& ) ), this, SLOT( audioInputError( const QString& ) ) );
34 }
35
36 void MagRead::maemoNotice( QString msg, int msec ) {
37         QMaemo5InformationBox infoBox;
38
39         infoBox.information( 0, msg, msec );
40         infoBox.show();
41 }
42
43 void MagRead::cardRead( const MagCard _card ) {
44         card = _card;
45         cardDetect.setCard( &card );
46
47         if( card.type & MagCard::CARD_CC && card.accountValid ) {
48                 creditPage();
49         } else if( card.type == MagCard::CARD_AAMVA ) {
50                 aamvaPage();
51         } else if( card.swipeValid ) {
52                 miscPage();
53         } else if( partialRead ) {
54                 maemoNotice( "Show data from a partial read; may be incomplete/invalid!", 1000 );
55                 miscPage( true );
56         } else {
57                 maemoNotice( "Swipe Failed! Please Retry", 1000 );
58         }
59 }
60
61 void MagRead::audioInputError( const QString msg ) {
62         maemoNotice( msg, 5000 );
63         captureAudio = false;
64 }
65
66 /* Main Page */
67 void MagRead::mainPage() {
68         QWidget *widget = new QWidget;
69         QVBoxLayout *layout = new QVBoxLayout( widget );
70
71         widget->setLayout( layout );
72
73         QLabel *label;
74         label = new QLabel( "<span style=\"font-size:48pt;\">MagRead</span>" );
75         layout->addWidget( label, 1, Qt::AlignHCenter );
76
77         QCheckBox *cbox = new QCheckBox( "Show Partial Data" );
78         layout->addWidget( cbox );
79         connect( cbox, SIGNAL( toggled( bool ) ), this, SLOT( togglePartialRead( bool ) ) );
80
81         QPushButton *button = new QPushButton( "Start" );
82         layout->addWidget( button );
83         connect( button, SIGNAL( clicked() ), this, SLOT( toggleRead() ) );
84
85         onMainPage = true;
86
87         setCentralWidget( widget );
88 }
89
90 void MagRead::toggleRead() {
91         QPushButton *button = qobject_cast<QPushButton *>( QObject::sender() );
92
93         if( captureAudio ) {
94                 audioInput.stop();
95                 if( onMainPage )
96                         button->setText( "Start" );
97                 else
98                         button->setText( "Back to Main Page" );
99                 captureAudio = false;
100         } else if( onMainPage ) {
101                 audioInput.start();
102                 button->setText( "Stop" );
103                 captureAudio = true;
104         } else {
105                 mainPage();
106         }
107
108 }
109
110 void MagRead::togglePartialRead( bool _partialRead ) {
111         partialRead = _partialRead;
112 }
113
114 /* Credit Page */
115 void MagRead::creditPage() {
116         maemoNotice( "Successfully Read Credit Card", 1000 );
117         QWidget *widget = new QWidget;
118         QGridLayout *layout = new QGridLayout( widget );
119
120         onMainPage = false;
121
122         widget->setLayout( layout );
123
124         QLabel *label;
125
126         QString accountNumber = card.accountNumber;
127         if( card.type == MagCard::CARD_AMEX ) {
128                 accountNumber.insert( 10, '\t' );
129                 accountNumber.insert( 4, '\t' );
130         } else {
131                 accountNumber.insert( 12, '\t' );
132                 accountNumber.insert( 8, '\t' );
133                 accountNumber.insert( 4, '\t' );
134         }
135
136         accountNumber.prepend( "<span style=\"font-size:48pt;\"><br>\n" );
137         accountNumber.append( "</span>" );
138         
139         if( !card.accountHolder.isEmpty() ) {
140                 accountNumber.append( "\n<span style=\"font-size:36pt;\"><div align=center>" );
141                 accountNumber.append( card.accountHolder );
142                 accountNumber.append( "</div></span>" );
143         }
144
145         label = new QLabel( accountNumber );
146         layout->addWidget( label, 0, 0, 1, 2, Qt::AlignHCenter );
147
148         label = new QLabel( "<span style=\"font-size:24pt;\">Expiration Date</span>" );
149         layout->addWidget( label, 1, 0, 1, 1, Qt::AlignHCenter | Qt::AlignBottom );
150
151         label = new QLabel( "<span style=\"font-size:24pt;\">Issuer</span>" );
152         layout->addWidget( label, 1, 1, 1, 1, Qt::AlignHCenter | Qt::AlignBottom );
153
154         QString expDate = card.expirationDate.toString( "MM/yy" );
155         if( card.expirationDate < QDate::currentDate() ) {
156                 expDate.prepend( "<font color=\"red\">" );
157                 expDate.append( "</font>" );
158         }
159
160         label = new QLabel( QString( "<span style=\"font-size:32pt;\">%1</span>" ).arg( expDate ) );
161         layout->addWidget( label, 2, 0, 1, 1, Qt::AlignHCenter | Qt::AlignTop );
162
163         label = new QLabel( QString( "<span style=\"font-size:32pt;\">%1</span>" ).arg( card.accountIssuer ) );
164         layout->addWidget( label, 2, 1, 1, 1, Qt::AlignHCenter | Qt::AlignTop );
165
166         QPushButton *button = new QPushButton( "Stop" );
167         layout->addWidget( button, 3, 0, 1, 2 );
168         connect( button, SIGNAL( clicked() ), this, SLOT( toggleRead() ) );
169
170         setCentralWidget( widget );
171 }
172
173 void MagRead::aamvaPage() {
174         maemoNotice( "Successfully Read AAMVA Card", 1000 );
175         QWidget *widget = new QWidget;
176         QGridLayout *layout = new QGridLayout( widget );
177
178         onMainPage = false;
179
180         widget->setLayout( layout );
181
182         QLabel *label;
183
184         label = new QLabel( "<span style=\"font-size:36pt;\">" + card.aamvaIssuerName + "</span>" );
185         layout->addWidget( label, 0, 0, 1, 2, Qt::AlignHCenter );
186
187         label = new QLabel( "<span style=\"font-size:32pt;\">" + card.accountNumber + "</span>" );
188         layout->addWidget( label, 1, 0, 1 ,2, Qt::AlignHCenter | Qt::AlignTop );
189         layout->setRowStretch( 1, 1 );
190
191         /* Calculate the age */
192         QDate curDate = QDate::currentDate();
193
194         QString ageStr = QString ( "<span style=\"font-size:32pt;\">Age %1 </span>" ).arg( card.aamvaAge );
195         if( card.aamvaAge < 18 ) {
196                 ageStr.prepend( "<font color=\"red\">" );
197                 ageStr.append( "</font>" );
198         } else if( card.aamvaAge < 21 ) {
199                 ageStr.prepend( "<font color=\"yellow\">" );
200                 ageStr.append( "</font>" );
201         }
202
203         label = new QLabel( ageStr );
204         layout->addWidget( label, 2, 0, 1, 2, Qt::AlignHCenter );
205
206         label = new QLabel( "<span style=\"font-size:24pt;\">Expiration Date</font>" );
207         layout->addWidget( label, 3, 0, 1, 1, Qt::AlignHCenter );
208
209         label = new QLabel( "<span style=\"font-size:24pt;\">Date of Birth</span>" );
210         layout->addWidget( label, 3, 1, 1, 1, Qt::AlignHCenter );
211
212         QString expDate = card.expirationDate.toString( "MM/dd/yy" );
213         expDate.prepend( "<span style=\"font-size:24pt;\">" );
214         if( card.expirationDate < QDate::currentDate() ) {
215                 expDate.prepend( "<font color=\"red\"><div align=\"center\">" );
216                 expDate.append( "<br>\nEXPIRED</font></div>" );
217         }
218         expDate.append( "</span>" );
219         label = new QLabel( expDate );
220         layout->addWidget( label, 4, 0, 1, 1, Qt::AlignHCenter );
221
222
223         label = new QLabel(  "<span style=\"font-size:24pt;\">" + card.aamvaBirthday.toString( "MM/dd/yy" ) + "</span>" );
224         layout->addWidget( label, 4, 1, 1, 1, Qt::AlignHCenter );
225
226         QPushButton *button = new QPushButton( "Stop" );
227         layout->addWidget( button, 5, 0, 1, 2 );
228         connect( button, SIGNAL( clicked() ), this, SLOT( toggleRead() ) );
229
230         setCentralWidget( widget );
231 }
232
233 /* Misc Page */
234 void MagRead::miscPage( bool partial ) {
235         if( !partial )
236                 maemoNotice( "Successfully Read an Unknown Card", 1000 );
237         
238         QWidget *widget = new QWidget;
239         QGridLayout *layout = new QGridLayout( widget );
240
241         onMainPage = false;
242
243         widget->setLayout( layout );
244
245         QScrollArea *scroll = new QScrollArea;
246
247         QString tmpStr = card.charStream;
248         if( tmpStr.contains( '%' ) ) {
249                 tmpStr.replace( '^', "<br>\n[Field Separator]<br>\n" );
250         } else {
251                 tmpStr.replace( '=', "<br>\n[Field Separator]<br>\n" );
252         }
253         tmpStr.replace( '|', "<font color=\"red\">|</font>" );
254
255         tmpStr.prepend( "<span style=\"font-size:36pt;\"><div align=\"center\">" );
256         tmpStr.append( "</div></span>" );
257
258         QLabel *label = new QLabel( tmpStr );
259         scroll->setWidget( label );
260         scroll->setWidgetResizable( true );
261         layout->addWidget( scroll, 0, 0, 1, 2, Qt::AlignHCenter );
262
263         label->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
264
265         QPushButton *button = new QPushButton( "Stop" );
266         layout->addWidget( button, 1, 0, 1, 2 );
267         connect( button, SIGNAL( clicked() ), this, SLOT( toggleRead() ) );
268
269         setCentralWidget( widget );
270 }
271