2 // AITranslatorRequestDelegate.m
4 // Created by Evan Schoenberg on 3/12/06.
6 /* Response decoding based on:
10 * Created by Alan Humpherys on Wed Mar 19 2003.
11 * Copyright (c) 2003. All rights reserved.
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #import "AITranslatorRequestDelegate.h"
29 #import "TranslationEngine.h"
30 #import "AITranslatorPlugin.h"
31 #import <AIUtilities/AIStringAdditions.h>
33 @interface AITranslatorRequestDelegate (PRIVATE)
34 - (id)initWithDict:(NSDictionary *)inDict notifyingTarget:(id)inTarget;
37 @implementation AITranslatorRequestDelegate
38 + (id)translatorRequestDelegateForDict:(NSDictionary *)inDict notifyingTarget:(id)inTarget
40 return [[[self alloc] initWithDict:inDict notifyingTarget:inTarget] autorelease];
43 - (id)initWithDict:(NSDictionary *)inDict notifyingTarget:(id)inTarget
45 if ((self = [super init])) {
46 messageDict = [inDict retain];
47 target = [inTarget retain];
48 state = Translator_SearchForTextArea;
49 response = [[NSMutableString alloc] init];
50 targetRange = NSMakeRange(0,0);
59 [messageDict release];
66 - (void)searchCompletedWithLocation:(int)location
68 NSString *translation;
70 // Reset the Range to reflect the returned translation
71 targetRange = NSMakeRange(0, location);
73 // We may have some newlines and spaces at the beginning of the range. If we do, let's
75 while ([response characterAtIndex:(targetRange.location)] == '\n' ||
76 [response characterAtIndex:(targetRange.location)] == '\r' ||
77 [response characterAtIndex:(targetRange.location)] == ' ') {
78 targetRange.location++;
82 // Now we might have some extra newlines and spaces at the end of our range. Let's
84 while ([response characterAtIndex:(targetRange.location+targetRange.length-1)] == '\n' ||
85 [response characterAtIndex:(targetRange.location+targetRange.length-1)] == '\r' ||
86 [response characterAtIndex:(targetRange.location+targetRange.length-1)] == ' ') {
90 translation = [response substringWithRange:targetRange];
92 if (!translation || [translation length] == 0) {
93 TRANSLATION_ERROR(TE_UNKNOWN_ERROR);
97 // The worldlingo website may add a meta tag to the start of the returned string. We must delete this
98 // tag because the clients do not understand it.
99 targetRange = [translation rangeOfString:@"<meta "];
100 if (targetRange.location != NSNotFound) {
101 NSRange endRange = [translation rangeOfString:@">"
102 options:NSLiteralSearch
103 range:NSMakeRange(targetRange.location + targetRange.length,
104 [translation length] - targetRange.location - targetRange.length)];
106 if (endRange.location != NSNotFound) {
107 response = [NSMutableString stringWithString:translation];
108 [response deleteCharactersInRange:NSMakeRange(targetRange.location,endRange.location - targetRange.location + 1)];
110 // Make a copy to ensure type integrity
111 translation = [NSString stringWithString:response];
115 [target translatedString:translation forMessageDict:messageDict];
118 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
120 // The target looks like:
121 // <textarea name="wl_result"...>This is what we're looking for.</textarea>
122 // Receive characters from the server. We'll keep going as long as
123 // we haven't found the closing </textarea>
124 if (state != Translator_SearchCompleted) {
125 NSString *retrievedData = [NSString stringWithData:data encoding:NSUTF8StringEncoding];
126 if (retrievedData && [retrievedData length]) {
127 [response appendString:retrievedData];
129 AILog(@"Null new data.. %@ so far...",response);
133 case Translator_SearchForTextArea:
135 targetRange = [response rangeOfString:@"<textarea name=\"wl_result\""];
136 if (targetRange.location == NSNotFound) {
139 // found textarea beginning
140 state = Translator_SearchForEndOfTag;
141 // Throw away all preamble data
142 targetRange.length = targetRange.location + targetRange.length;
143 targetRange.location = 0;
144 [response deleteCharactersInRange:targetRange];
145 // fall through to next state
148 case Translator_SearchForEndOfTag:
150 targetRange = [response rangeOfString:@">"];
151 if (targetRange.location == NSNotFound) {
154 // found closing of <textarea *> tag
155 state = Translator_SearchForTextAreaClose;
156 // Throw away all preamble data
157 targetRange.length = targetRange.location + targetRange.length;
158 targetRange.location = 0;
159 [response deleteCharactersInRange:targetRange];
160 // fall through to next state
163 case Translator_SearchForTextAreaClose:
165 targetRange = [response rangeOfString:@"</textarea>"];
166 if (targetRange.location != NSNotFound) {
167 // found closing of </textarea> tag
168 state = Translator_SearchCompleted;
172 case Translator_SearchCompleted:
176 if (!response || [response length] == 0) {
177 TRANSLATION_ERROR(TE_NO_RESPONSE);
182 if (state == Translator_SearchCompleted) {
183 if (targetRange.location == 0) {
184 TRANSLATION_ERROR(TE_EMPTY_RESPONSE);
188 [self searchCompletedWithLocation:targetRange.location];
193 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
195 AILog(@"Translation failed: %@", [error localizedDescription]);
198 -(void)connectionDidFinishLoading:(NSURLConnection *)connection
200 if (state != Translator_SearchCompleted) {
201 TRANSLATION_ERROR(TE_CANT_DECODE);