summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Martin Szulecki2010-01-05 04:52:50 +0100
committerGravatar Martin Szulecki2010-01-05 04:52:50 +0100
commite0cf27624accbcd49ff628919a2546685e3136d9 (patch)
tree0009f001df8e971813e363a2d8036caad261d3f0
downloadideviceinstaller-e0cf27624accbcd49ff628919a2546685e3136d9.tar.gz
ideviceinstaller-e0cf27624accbcd49ff628919a2546685e3136d9.tar.bz2
Commit initial sources
-rw-r--r--.gitignore34
-rw-r--r--AUTHORS1
-rw-r--r--COPYING340
-rw-r--r--Makefile.am4
-rw-r--r--README15
-rwxr-xr-xautogen.sh10
-rw-r--r--configure.ac48
-rw-r--r--m4/as-compiler-flag.m462
-rw-r--r--src/Makefile.am17
-rw-r--r--src/iphoneinstaller.c982
10 files changed, 1513 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..58b2f17
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,34 @@
1# git-ls-files --others --exclude-from=.git/info/exclude
2# Lines that start with '#' are comments.
3# For a project mostly in C, the following would be a good set of
4# exclude patterns (uncomment them if you want to use them):
5*.[oa]
6*~
7*.po
8*.lo
9*.la
10autom4te.cache/*
11*.in
12*/.deps/*
13m4/*
14*.swp
15aclocal.m4
16config.h
17config.log
18config.sub
19config.guess
20config.status
21configure
22depcomp
23install-sh
24compile
25main
26ltmain.sh
27missing
28mkinstalldirs
29libtool
30*Makefile
31stamp-h1
32src/.libs
33src/sbmanager
34data/data.h
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..b818ec5
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
Nikias Bassen
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..08ddefd
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
1 GNU GENERAL PUBLIC LICENSE
2 Version 2, June 1991
3
4 Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 Everyone is permitted to copy and distribute verbatim copies
7 of this license document, but changing it is not allowed.
8
9 Preamble
10
11 The licenses for most software are designed to take away your
12freedom to share and change it. By contrast, the GNU General Public
13License is intended to guarantee your freedom to share and change free
14software--to make sure the software is free for all its users. This
15General Public License applies to most of the Free Software
16Foundation's software and to any other program whose authors commit to
17using it. (Some other Free Software Foundation software is covered by
18the GNU Lesser General Public License instead.) You can apply it to
19your programs, too.
20
21 When we speak of free software, we are referring to freedom, not
22price. Our General Public Licenses are designed to make sure that you
23have the freedom to distribute copies of free software (and charge for
24this service if you wish), that you receive source code or can get it
25if you want it, that you can change the software or use pieces of it
26in new free programs; and that you know you can do these things.
27
28 To protect your rights, we need to make restrictions that forbid
29anyone to deny you these rights or to ask you to surrender the rights.
30These restrictions translate to certain responsibilities for you if you
31distribute copies of the software, or if you modify it.
32
33 For example, if you distribute copies of such a program, whether
34gratis or for a fee, you must give the recipients all the rights that
35you have. You must make sure that they, too, receive or can get the
36source code. And you must show them these terms so they know their
37rights.
38
39 We protect your rights with two steps: (1) copyright the software, and
40(2) offer you this license which gives you legal permission to copy,
41distribute and/or modify the software.
42
43 Also, for each author's protection and ours, we want to make certain
44that everyone understands that there is no warranty for this free
45software. If the software is modified by someone else and passed on, we
46want its recipients to know that what they have is not the original, so
47that any problems introduced by others will not reflect on the original
48authors' reputations.
49
50 Finally, any free program is threatened constantly by software
51patents. We wish to avoid the danger that redistributors of a free
52program will individually obtain patent licenses, in effect making the
53program proprietary. To prevent this, we have made it clear that any
54patent must be licensed for everyone's free use or not licensed at all.
55
56 The precise terms and conditions for copying, distribution and
57modification follow.
58
59 GNU GENERAL PUBLIC LICENSE
60 TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
62 0. This License applies to any program or other work which contains
63a notice placed by the copyright holder saying it may be distributed
64under the terms of this General Public License. The "Program", below,
65refers to any such program or work, and a "work based on the Program"
66means either the Program or any derivative work under copyright law:
67that is to say, a work containing the Program or a portion of it,
68either verbatim or with modifications and/or translated into another
69language. (Hereinafter, translation is included without limitation in
70the term "modification".) Each licensee is addressed as "you".
71
72Activities other than copying, distribution and modification are not
73covered by this License; they are outside its scope. The act of
74running the Program is not restricted, and the output from the Program
75is covered only if its contents constitute a work based on the
76Program (independent of having been made by running the Program).
77Whether that is true depends on what the Program does.
78
79 1. You may copy and distribute verbatim copies of the Program's
80source code as you receive it, in any medium, provided that you
81conspicuously and appropriately publish on each copy an appropriate
82copyright notice and disclaimer of warranty; keep intact all the
83notices that refer to this License and to the absence of any warranty;
84and give any other recipients of the Program a copy of this License
85along with the Program.
86
87You may charge a fee for the physical act of transferring a copy, and
88you may at your option offer warranty protection in exchange for a fee.
89
90 2. You may modify your copy or copies of the Program or any portion
91of it, thus forming a work based on the Program, and copy and
92distribute such modifications or work under the terms of Section 1
93above, provided that you also meet all of these conditions:
94
95 a) You must cause the modified files to carry prominent notices
96 stating that you changed the files and the date of any change.
97
98 b) You must cause any work that you distribute or publish, that in
99 whole or in part contains or is derived from the Program or any
100 part thereof, to be licensed as a whole at no charge to all third
101 parties under the terms of this License.
102
103 c) If the modified program normally reads commands interactively
104 when run, you must cause it, when started running for such
105 interactive use in the most ordinary way, to print or display an
106 announcement including an appropriate copyright notice and a
107 notice that there is no warranty (or else, saying that you provide
108 a warranty) and that users may redistribute the program under
109 these conditions, and telling the user how to view a copy of this
110 License. (Exception: if the Program itself is interactive but
111 does not normally print such an announcement, your work based on
112 the Program is not required to print an announcement.)
113
114These requirements apply to the modified work as a whole. If
115identifiable sections of that work are not derived from the Program,
116and can be reasonably considered independent and separate works in
117themselves, then this License, and its terms, do not apply to those
118sections when you distribute them as separate works. But when you
119distribute the same sections as part of a whole which is a work based
120on the Program, the distribution of the whole must be on the terms of
121this License, whose permissions for other licensees extend to the
122entire whole, and thus to each and every part regardless of who wrote it.
123
124Thus, it is not the intent of this section to claim rights or contest
125your rights to work written entirely by you; rather, the intent is to
126exercise the right to control the distribution of derivative or
127collective works based on the Program.
128
129In addition, mere aggregation of another work not based on the Program
130with the Program (or with a work based on the Program) on a volume of
131a storage or distribution medium does not bring the other work under
132the scope of this License.
133
134 3. You may copy and distribute the Program (or a work based on it,
135under Section 2) in object code or executable form under the terms of
136Sections 1 and 2 above provided that you also do one of the following:
137
138 a) Accompany it with the complete corresponding machine-readable
139 source code, which must be distributed under the terms of Sections
140 1 and 2 above on a medium customarily used for software interchange; or,
141
142 b) Accompany it with a written offer, valid for at least three
143 years, to give any third party, for a charge no more than your
144 cost of physically performing source distribution, a complete
145 machine-readable copy of the corresponding source code, to be
146 distributed under the terms of Sections 1 and 2 above on a medium
147 customarily used for software interchange; or,
148
149 c) Accompany it with the information you received as to the offer
150 to distribute corresponding source code. (This alternative is
151 allowed only for noncommercial distribution and only if you
152 received the program in object code or executable form with such
153 an offer, in accord with Subsection b above.)
154
155The source code for a work means the preferred form of the work for
156making modifications to it. For an executable work, complete source
157code means all the source code for all modules it contains, plus any
158associated interface definition files, plus the scripts used to
159control compilation and installation of the executable. However, as a
160special exception, the source code distributed need not include
161anything that is normally distributed (in either source or binary
162form) with the major components (compiler, kernel, and so on) of the
163operating system on which the executable runs, unless that component
164itself accompanies the executable.
165
166If distribution of executable or object code is made by offering
167access to copy from a designated place, then offering equivalent
168access to copy the source code from the same place counts as
169distribution of the source code, even though third parties are not
170compelled to copy the source along with the object code.
171
172 4. You may not copy, modify, sublicense, or distribute the Program
173except as expressly provided under this License. Any attempt
174otherwise to copy, modify, sublicense or distribute the Program is
175void, and will automatically terminate your rights under this License.
176However, parties who have received copies, or rights, from you under
177this License will not have their licenses terminated so long as such
178parties remain in full compliance.
179
180 5. You are not required to accept this License, since you have not
181signed it. However, nothing else grants you permission to modify or
182distribute the Program or its derivative works. These actions are
183prohibited by law if you do not accept this License. Therefore, by
184modifying or distributing the Program (or any work based on the
185Program), you indicate your acceptance of this License to do so, and
186all its terms and conditions for copying, distributing or modifying
187the Program or works based on it.
188
189 6. Each time you redistribute the Program (or any work based on the
190Program), the recipient automatically receives a license from the
191original licensor to copy, distribute or modify the Program subject to
192these terms and conditions. You may not impose any further
193restrictions on the recipients' exercise of the rights granted herein.
194You are not responsible for enforcing compliance by third parties to
195this License.
196
197 7. If, as a consequence of a court judgment or allegation of patent
198infringement or for any other reason (not limited to patent issues),
199conditions are imposed on you (whether by court order, agreement or
200otherwise) that contradict the conditions of this License, they do not
201excuse you from the conditions of this License. If you cannot
202distribute so as to satisfy simultaneously your obligations under this
203License and any other pertinent obligations, then as a consequence you
204may not distribute the Program at all. For example, if a patent
205license would not permit royalty-free redistribution of the Program by
206all those who receive copies directly or indirectly through you, then
207the only way you could satisfy both it and this License would be to
208refrain entirely from distribution of the Program.
209
210If any portion of this section is held invalid or unenforceable under
211any particular circumstance, the balance of the section is intended to
212apply and the section as a whole is intended to apply in other
213circumstances.
214
215It is not the purpose of this section to induce you to infringe any
216patents or other property right claims or to contest validity of any
217such claims; this section has the sole purpose of protecting the
218integrity of the free software distribution system, which is
219implemented by public license practices. Many people have made
220generous contributions to the wide range of software distributed
221through that system in reliance on consistent application of that
222system; it is up to the author/donor to decide if he or she is willing
223to distribute software through any other system and a licensee cannot
224impose that choice.
225
226This section is intended to make thoroughly clear what is believed to
227be a consequence of the rest of this License.
228
229 8. If the distribution and/or use of the Program is restricted in
230certain countries either by patents or by copyrighted interfaces, the
231original copyright holder who places the Program under this License
232may add an explicit geographical distribution limitation excluding
233those countries, so that distribution is permitted only in or among
234countries not thus excluded. In such case, this License incorporates
235the limitation as if written in the body of this License.
236
237 9. The Free Software Foundation may publish revised and/or new versions
238of the General Public License from time to time. Such new versions will
239be similar in spirit to the present version, but may differ in detail to
240address new problems or concerns.
241
242Each version is given a distinguishing version number. If the Program
243specifies a version number of this License which applies to it and "any
244later version", you have the option of following the terms and conditions
245either of that version or of any later version published by the Free
246Software Foundation. If the Program does not specify a version number of
247this License, you may choose any version ever published by the Free Software
248Foundation.
249
250 10. If you wish to incorporate parts of the Program into other free
251programs whose distribution conditions are different, write to the author
252to ask for permission. For software which is copyrighted by the Free
253Software Foundation, write to the Free Software Foundation; we sometimes
254make exceptions for this. Our decision will be guided by the two goals
255of preserving the free status of all derivatives of our free software and
256of promoting the sharing and reuse of software generally.
257
258 NO WARRANTY
259
260 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268REPAIR OR CORRECTION.
269
270 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278POSSIBILITY OF SUCH DAMAGES.
279
280 END OF TERMS AND CONDITIONS
281
282 How to Apply These Terms to Your New Programs
283
284 If you develop a new program, and you want it to be of the greatest
285possible use to the public, the best way to achieve this is to make it
286free software which everyone can redistribute and change under these terms.
287
288 To do so, attach the following notices to the program. It is safest
289to attach them to the start of each source file to most effectively
290convey the exclusion of warranty; and each file should have at least
291the "copyright" line and a pointer to where the full notice is found.
292
293 <one line to give the program's name and a brief idea of what it does.>
294 Copyright (C) <year> <name of author>
295
296 This program is free software; you can redistribute it and/or modify
297 it under the terms of the GNU General Public License as published by
298 the Free Software Foundation; either version 2 of the License, or
299 (at your option) any later version.
300
301 This program is distributed in the hope that it will be useful,
302 but WITHOUT ANY WARRANTY; without even the implied warranty of
303 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 GNU General Public License for more details.
305
306 You should have received a copy of the GNU General Public License along
307 with this program; if not, write to the Free Software Foundation, Inc.,
308 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309
310Also add information on how to contact you by electronic and paper mail.
311
312If the program is interactive, make it output a short notice like this
313when it starts in an interactive mode:
314
315 Gnomovision version 69, Copyright (C) year name of author
316 Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 This is free software, and you are welcome to redistribute it
318 under certain conditions; type `show c' for details.
319
320The hypothetical commands `show w' and `show c' should show the appropriate
321parts of the General Public License. Of course, the commands you use may
322be called something other than `show w' and `show c'; they could even be
323mouse-clicks or menu items--whatever suits your program.
324
325You should also get your employer (if you work as a programmer) or your
326school, if any, to sign a "copyright disclaimer" for the program, if
327necessary. Here is a sample; alter the names:
328
329 Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 `Gnomovision' (which makes passes at compilers) written by James Hacker.
331
332 <signature of Ty Coon>, 1 April 1989
333 Ty Coon, President of Vice
334
335This General Public License does not permit incorporating your program into
336proprietary programs. If your program is a subroutine library, you may
337consider it more useful to permit linking proprietary applications with the
338library. If this is what you want to do, use the GNU Lesser General
339Public License instead of this License.
340
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..4c3e7c3
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,4 @@
1AUTOMAKE_OPTIONS = foreign
2ACLOCAL_AMFLAGS = -I m4
3SUBDIRS = src
4
diff --git a/README b/README
new file mode 100644
index 0000000..1658dcd
--- /dev/null
+++ b/README
@@ -0,0 +1,15 @@
1iphoneinstaller
2----------
3
4iphoneinstaller is a tool to interact with the installation_proxy
5of an iPhone/iPod Touch device allowing to install, upgrade, uninstall,
6archive, restore, and enumerate installed or archived apps.
7
8It makes use of the libiphone library that allows communication
9with the devices.
10
11For more information:
12 http://matt.colyer.name/projects/iphone-linux/
13
14README updated on:
15 2010-01-04
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..cb3887a
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,10 @@
1#!/bin/sh
2aclocal -I m4
3libtoolize
4autoheader
5automake --add-missing
6autoconf
7
8if [ -z "$NOCONFIGURE" ]; then
9 ./configure "$@"
10fi
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..790e004
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,48 @@
1# -*- Autoconf -*-
2# Process this file with autoconf to produce a configure script.
3
4AC_PREREQ(2.61)
5AC_INIT(iphoneinstaller, 1.0.0, nospam@nowhere.com)
6AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip])
7m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES])
8AC_CONFIG_SRCDIR([src/])
9AC_CONFIG_HEADERS([config.h])
10AC_CONFIG_MACRO_DIR([m4])
11
12# Checks for programs.
13AC_PROG_CC
14AM_PROG_CC_C_O
15AC_PROG_LIBTOOL
16
17# Checks for libraries.
18PKG_CHECK_MODULES(libiphone, libiphone-1.0)
19PKG_CHECK_MODULES(libplist, libplist >= 0.15)
20PKG_CHECK_MODULES(libzip, libzip >= 0.8)
21
22# Checks for header files.
23AC_HEADER_STDC
24AC_CHECK_HEADERS([stdint.h stdlib.h string.h])
25
26# Checks for typedefs, structures, and compiler characteristics.
27AC_C_CONST
28AC_TYPE_SIZE_T
29AC_TYPE_SSIZE_T
30AC_TYPE_UINT16_T
31AC_TYPE_UINT32_T
32AC_TYPE_UINT8_T
33
34# Checks for library functions.
35AC_FUNC_MALLOC
36AC_FUNC_REALLOC
37AC_CHECK_FUNCS([strcasecmp strdup strerror strndup])
38
39AS_COMPILER_FLAGS(GLOBAL_CFLAGS, "-Wall -Wextra -Wmissing-declarations -Wredundant-decls -Wshadow -Wpointer-arith -Wwrite-strings -Wswitch-default -Wno-unused-parameter -Werror -g")
40AC_SUBST(GLOBAL_CFLAGS)
41
42m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
43
44AC_OUTPUT([
45Makefile
46src/Makefile
47])
48
diff --git a/m4/as-compiler-flag.m4 b/m4/as-compiler-flag.m4
new file mode 100644
index 0000000..0f660cf
--- /dev/null
+++ b/m4/as-compiler-flag.m4
@@ -0,0 +1,62 @@
1dnl as-compiler-flag.m4 0.1.0
2
3dnl autostars m4 macro for detection of compiler flags
4
5dnl David Schleef <ds@schleef.org>
6
7dnl $Id: as-compiler-flag.m4,v 1.1 2005/12/15 23:35:19 ds Exp $
8
9dnl AS_COMPILER_FLAG(CFLAGS, ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED])
10dnl Tries to compile with the given CFLAGS.
11dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags,
12dnl and ACTION-IF-NOT-ACCEPTED otherwise.
13
14AC_DEFUN([AS_COMPILER_FLAG],
15[
16 AC_MSG_CHECKING([to see if compiler understands $1])
17
18 save_CFLAGS="$CFLAGS"
19 CFLAGS="$CFLAGS $1"
20
21 AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no])
22 CFLAGS="$save_CFLAGS"
23
24 if test "X$flag_ok" = Xyes ; then
25 m4_ifvaln([$2],[$2])
26 true
27 else
28 m4_ifvaln([$3],[$3])
29 true
30 fi
31 AC_MSG_RESULT([$flag_ok])
32])
33
34dnl AS_COMPILER_FLAGS(VAR, FLAGS)
35dnl Tries to compile with the given CFLAGS.
36
37AC_DEFUN([AS_COMPILER_FLAGS],
38[
39 list=$2
40 flags_supported=""
41 flags_unsupported=""
42 AC_MSG_CHECKING([for supported compiler flags])
43 for each in $list
44 do
45 save_CFLAGS="$CFLAGS"
46 CFLAGS="$CFLAGS $each"
47 AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no])
48 CFLAGS="$save_CFLAGS"
49
50 if test "X$flag_ok" = Xyes ; then
51 flags_supported="$flags_supported $each"
52 else
53 flags_unsupported="$flags_unsupported $each"
54 fi
55 done
56 AC_MSG_RESULT([$flags_supported])
57 if test "X$flags_unsupported" != X ; then
58 AC_MSG_WARN([unsupported compiler flags: $flags_unsupported])
59 fi
60 $1="$$1 $flags_supported"
61])
62
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..028e2e1
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,17 @@
1AM_CFLAGS = \
2 $(GLOBAL_CFLAGS) \
3 $(libiphone_CFLAGS) \
4 $(libplist_CFLAGS) \
5 $(libzip_CFLAGS)
6
7AM_LDFLAGS = \
8 $(libiphone_LIBS) \
9 $(libplist_LIBS) \
10 $(libzip_LIBS)
11
12bin_PROGRAMS = iphoneinstaller
13
14iphoneinstaller_SOURCES = iphoneinstaller.c
15iphoneinstaller_CFLAGS = $(AM_CFLAGS)
16iphoneinstaller_LDFLAGS = $(AM_LDFLAGS)
17
diff --git a/src/iphoneinstaller.c b/src/iphoneinstaller.c
new file mode 100644
index 0000000..d3e311c
--- /dev/null
+++ b/src/iphoneinstaller.c
@@ -0,0 +1,982 @@
1/**
2 * iphoneinstaller -- Manage iPhone/iPod apps
3 *
4 * Copyright (C) 2010 Nikias Bassen <nikias@gmx.li>
5 *
6 * Licensed under the GNU General Public License Version 2
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more profile.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
21 * USA
22 */
23#include <stdlib.h>
24#define _GNU_SOURCE 1
25#define __USE_GNU 1
26#include <stdio.h>
27#include <string.h>
28#include <getopt.h>
29#include <errno.h>
30#include <time.h>
31
32#include <libiphone/libiphone.h>
33#include <libiphone/lockdown.h>
34#include <libiphone/installation_proxy.h>
35#include <libiphone/notification_proxy.h>
36#include <libiphone/afc.h>
37
38#include <plist/plist.h>
39
40#include <zip.h>
41
42const char PKG_PATH[] = "PublicStaging";
43const char APPARCH_PATH[] = "ApplicationArchives";
44
45char *uuid = NULL;
46char *options = NULL;
47char *appid = NULL;
48
49int list_apps_mode = 0;
50int install_mode = 0;
51int uninstall_mode = 0;
52int upgrade_mode = 0;
53int list_archives_mode = 0;
54int archive_mode = 0;
55int restore_mode = 0;
56int remove_archive_mode = 0;
57
58char *last_status = NULL;
59int wait_for_op_complete = 0;
60int notification_expected = 0;
61int op_completed = 0;
62int err_occured = 0;
63int notified = 0;
64
65
66static void notifier(const char *notification)
67{
68 /* printf("notification received: %s\n", notification);*/
69 notified = 1;
70}
71
72static void status_cb(const char *operation, plist_t status)
73{
74 if (status && operation) {
75 plist_t npercent = plist_dict_get_item(status, "PercentComplete");
76 plist_t nstatus = plist_dict_get_item(status, "Status");
77 plist_t nerror = plist_dict_get_item(status, "Error");
78 int percent = 0;
79 char *status_msg = NULL;
80 if (npercent) {
81 uint64_t val = 0;
82 plist_get_uint_val(npercent, &val);
83 percent = val;
84 }
85 if (nstatus) {
86 plist_get_string_val(nstatus, &status_msg);
87 if (!strcmp(status_msg, "Complete")) {
88 op_completed = 1;
89 }
90 }
91 if (!nerror) {
92 if (last_status && (strcmp(last_status, status_msg))) {
93 printf("\n");
94 }
95
96 if (!npercent) {
97 printf("%s - %s\n", operation, status_msg);
98 } else {
99 printf("%s - %s (%d%%)\r", operation, status_msg, percent);
100 }
101 } else {
102 char *err_msg = NULL;
103 plist_get_string_val(nerror, &err_msg);
104 printf("%s - Error occured: %s\n", operation, err_msg);
105 free(err_msg);
106 err_occured = 1;
107 }
108 if (last_status) {
109 free(last_status);
110 last_status = NULL;
111 }
112 if (status_msg) {
113 last_status = strdup(status_msg);
114 free(status_msg);
115 }
116 } else {
117 printf("%s: called with invalid data!\n", __func__);
118 }
119}
120
121static int zip_f_get_contents(struct zip *zf, const char *filename, int locate_flags, char **buffer, uint32_t *len)
122{
123 struct zip_stat zs;
124 struct zip_file *zfile;
125 int zindex = zip_name_locate(zf, filename, locate_flags);
126
127 *buffer = NULL;
128 *len = 0;
129
130 if (zindex < 0) {
131 fprintf(stderr, "ERROR: could not locate %s in archive!\n", filename);
132 return -1;
133 }
134
135 zip_stat_init(&zs);
136
137 if (zip_stat_index(zf, zindex, 0, &zs) != 0) {
138 fprintf(stderr, "ERROR: zip_stat_index '%s' failed!\n", filename);
139 return -2;
140 }
141
142 if (zs.size > 10485760) {
143 fprintf(stderr, "ERROR: file '%s' is too large!\n", filename);
144 return -3;
145 }
146
147 zfile = zip_fopen_index(zf, zindex, 0);
148 if (!zfile) {
149 fprintf(stderr, "ERROR: zip_fopen '%s' failed!\n", filename);
150 return -4;
151 }
152
153 *buffer = malloc(zs.size);
154 if (zip_fread(zfile, *buffer, zs.size) != zs.size) {
155 fprintf(stderr, "ERROR: zip_fread %ld bytes from '%s'\n", zs.size, filename);
156 free(*buffer);
157 *buffer = NULL;
158 zip_fclose(zfile);
159 return -5;
160 }
161 *len = zs.size;
162 zip_fclose(zfile);
163 return 0;
164}
165
166static void do_wait_when_needed()
167{
168 int i = 0;
169 struct timespec ts;
170 ts.tv_sec = 0;
171 ts.tv_nsec = 500000000;
172
173 /* wait for operation to complete */
174 while (wait_for_op_complete && !op_completed && !err_occured
175 && !notified && (i < 60)) {
176 nanosleep(&ts, NULL);
177 i++;
178 }
179
180 /* wait some time if a notification is expected */
181 while (notification_expected && !notified && !err_occured && (i < 10)) {
182 nanosleep(&ts, NULL);
183 i++;
184 }
185}
186
187static void print_usage(int argc, char **argv)
188{
189 char *name = NULL;
190
191 name = strrchr(argv[0], '/');
192 printf("Usage: %s OPTIONS\n", (name ? name + 1 : argv[0]));
193 printf
194 (" -U|--uuid UUID\tTarget specific device by its 40-digit device UUID.\n"
195 " -l|--list-apps\tList apps, possible options:\n"
196 " -o list_user\t- list user apps only (this is the default)\n"
197 " -o list_system\t- list system apps only\n"
198 " -o list_all\t- list all types of apps\n"
199 " -o xml\t\t- print full output as xml plist\n"
200 " -i|--install ARCHIVE\tInstall app from package file specified by ARCHIVE.\n"
201 " -u|--uninstall APPID\tUninstall app specified by APPID.\n"
202 " -g|--upgrade APPID\tUpgrade app specified by APPID.\n"
203 " -L|--list-archives\tList archived applications, possible options:\n"
204 " -o xml\t\t- print full output as xml plist\n"
205 " -a|--archive APPID\tArchive app specified by APPID, possible options:\n"
206 " -o uninstall\t- uninstall the package after making an archive\n"
207 " -o app_only\t- archive application data only\n"
208 " -o copy=PATH\t- copy the app archive to directory PATH when done\n"
209 " -o remove\t- only valid when copy=PATH is used: remove after copy\n"
210 " -r|--restore APPID\tRestore archived app specified by APPID\n"
211 " -R|--remove-archive APPID Remove app archive specified by APPID\n"
212 " -o|--options\t\tPass additional options to the specified command.\n"
213 " -h|--help\t\tprints usage information\n"
214 " -D|--debug\t\tenable communication debugging\n" "\n");
215}
216
217static void parse_opts(int argc, char **argv)
218{
219 static struct option longopts[] = {
220 {"help", 0, NULL, 'h'},
221 {"uuid", 0, NULL, 'U'},
222 {"list-apps", 0, NULL, 'l'},
223 {"install", 0, NULL, 'i'},
224 {"uninstall", 0, NULL, 'u'},
225 {"upgrade", 0, NULL, 'g'},
226 {"list-archives", 0, NULL, 'L'},
227 {"archive", 0, NULL, 'a'},
228 {"restore", 0, NULL, 'r'},
229 {"remove-archive", 0, NULL, 'R'},
230 {"options", 0, NULL, 'o'},
231 {"debug", 0, NULL, 'D'},
232 {NULL, 0, NULL, 0}
233 };
234 int c;
235
236 while (1) {
237 c = getopt_long(argc, argv, "hU:li:u:g:La:r:R:o:D", longopts,
238 (int *) 0);
239 if (c == -1) {
240 break;
241 }
242
243 switch (c) {
244 case 'h':
245 print_usage(argc, argv);
246 exit(0);
247 case 'U':
248 if (strlen(optarg) != 40) {
249 printf("%s: invalid UUID specified (length != 40)\n",
250 argv[0]);
251 print_usage(argc, argv);
252 exit(2);
253 }
254 uuid = strdup(optarg);
255 break;
256 case 'l':
257 list_apps_mode = 1;
258 break;
259 case 'i':
260 install_mode = 1;
261 appid = strdup(optarg);
262 break;
263 case 'u':
264 uninstall_mode = 1;
265 appid = strdup(optarg);
266 break;
267 case 'g':
268 upgrade_mode = 1;
269 appid = strdup(optarg);
270 break;
271 case 'L':
272 list_archives_mode = 1;
273 break;
274 case 'a':
275 archive_mode = 1;
276 appid = strdup(optarg);
277 break;
278 case 'r':
279 restore_mode = 1;
280 appid = strdup(optarg);
281 break;
282 case 'R':
283 remove_archive_mode = 1;
284 appid = strdup(optarg);
285 break;
286 case 'o':
287 if (!options) {
288 options = strdup(optarg);
289 } else {
290 char *newopts = malloc(strlen(options) + strlen(optarg) + 2);
291 strcpy(newopts, options);
292 free(options);
293 strcat(newopts, ",");
294 strcat(newopts, optarg);
295 options = newopts;
296 }
297 break;
298 case 'D':
299 iphone_set_debug_level(1);
300 iphone_set_debug_mask(DBGMASK_ALL);
301 break;
302 default:
303 print_usage(argc, argv);
304 exit(2);
305 }
306 }
307
308 if (optind <= 1 || (argc - optind > 0)) {
309 print_usage(argc, argv);
310 exit(2);
311 }
312}
313
314int main(int argc, char **argv)
315{
316 iphone_device_t phone = NULL;
317 lockdownd_client_t client = NULL;
318 instproxy_client_t ipc = NULL;
319 np_client_t np = NULL;
320 afc_client_t afc = NULL;
321 int port = 0;
322 int res = 0;
323
324 parse_opts(argc, argv);
325
326 argc -= optind;
327 argv += optind;
328
329 if (IPHONE_E_SUCCESS != iphone_device_new(&phone, uuid)) {
330 fprintf(stderr, "No iPhone found, is it plugged in?\n");
331 return -1;
332 }
333
334 if (LOCKDOWN_E_SUCCESS != lockdownd_client_new(phone, &client)) {
335 fprintf(stderr, "Could not connect to lockdownd. Exiting.\n");
336 goto leave_cleanup;
337 }
338
339 if ((lockdownd_start_service
340 (client, "com.apple.mobile.notification_proxy",
341 &port) != LOCKDOWN_E_SUCCESS) || !port) {
342 fprintf(stderr,
343 "Could not start com.apple.mobile.notification_proxy!\n");
344 goto leave_cleanup;
345 }
346
347 if (np_client_new(phone, port, &np) != NP_E_SUCCESS) {
348 fprintf(stderr, "Could not connect to notification_proxy!\n");
349 goto leave_cleanup;
350 }
351
352 np_set_notify_callback(np, notifier);
353
354 const char *noties[3] = { NP_APP_INSTALLED, NP_APP_UNINSTALLED, NULL };
355
356 np_observe_notifications(np, noties);
357
358run_again:
359 port = 0;
360 if ((lockdownd_start_service
361 (client, "com.apple.mobile.installation_proxy",
362 &port) != LOCKDOWN_E_SUCCESS) || !port) {
363 fprintf(stderr,
364 "Could not start com.apple.mobile.installation_proxy!\n");
365 goto leave_cleanup;
366 }
367
368 if (instproxy_client_new(phone, port, &ipc) != INSTPROXY_E_SUCCESS) {
369 fprintf(stderr, "Could not connect to installation_proxy!\n");
370 goto leave_cleanup;
371 }
372
373 setbuf(stdout, NULL);
374
375 if (last_status) {
376 free(last_status);
377 last_status = NULL;
378 }
379 notification_expected = 0;
380
381 if (list_apps_mode) {
382 int xml_mode = 0;
383 instproxy_apptype_t apptype = INSTPROXY_APPTYPE_USER;
384 instproxy_error_t err;
385 plist_t apps = NULL;
386
387 /* look for options */
388 if (options) {
389 char *opts = strdup(options);
390 char *elem = strtok(opts, ",");
391 while (elem) {
392 if (!strcmp(elem, "list_system")) {
393 apptype = INSTPROXY_APPTYPE_SYSTEM;
394 } else if (!strcmp(elem, "list_all")) {
395 apptype = INSTPROXY_APPTYPE_ALL;
396 } else if (!strcmp(elem, "list_user")) {
397 apptype = INSTPROXY_APPTYPE_USER;
398 } else if (!strcmp(elem, "xml")) {
399 xml_mode = 1;
400 }
401 elem = strtok(NULL, ",");
402 }
403 }
404
405 err = instproxy_browse(ipc, apptype, &apps);
406 if (err != INSTPROXY_E_SUCCESS) {
407 fprintf(stderr, "ERROR: instproxy_browse returned %d\n", err);
408 goto leave_cleanup;
409 }
410 if (!apps || (plist_get_node_type(apps) != PLIST_ARRAY)) {
411 fprintf(stderr,
412 "ERROR: instproxy_browse returnd an invalid plist!\n");
413 goto leave_cleanup;
414 }
415 if (xml_mode) {
416 char *xml = NULL;
417 uint32_t len = 0;
418
419 plist_to_xml(apps, &xml, &len);
420 if (xml) {
421 puts(xml);
422 free(xml);
423 }
424 plist_free(apps);
425 goto leave_cleanup;
426 }
427 printf("Total: %d apps\n", plist_array_get_size(apps));
428 uint32_t i = 0;
429 for (i = 0; i < plist_array_get_size(apps); i++) {
430 plist_t app = plist_array_get_item(apps, i);
431 plist_t p_appid =
432 plist_dict_get_item(app, "CFBundleIdentifier");
433 char *s_appid = NULL;
434 char *s_dispName = NULL;
435 char *s_version = NULL;
436 plist_t dispName =
437 plist_dict_get_item(app, "CFBundleDisplayName");
438 plist_t version = plist_dict_get_item(app, "CFBundleVersion");
439
440 if (p_appid) {
441 plist_get_string_val(p_appid, &s_appid);
442 }
443 if (!s_appid) {
444 fprintf(stderr, "ERROR: Failed to get APPID!\n");
445 break;
446 }
447
448 if (dispName) {
449 plist_get_string_val(dispName, &s_dispName);
450 }
451 if (version) {
452 plist_get_string_val(version, &s_version);
453 }
454
455 if (!s_dispName) {
456 s_dispName = strdup(s_appid);
457 }
458 if (s_version) {
459 printf("%s - %s %s\n", s_appid, s_dispName, s_version);
460 free(s_version);
461 } else {
462 printf("%s - %s\n", s_appid, s_dispName);
463 }
464 free(s_dispName);
465 free(s_appid);
466 }
467 plist_free(apps);
468 } else if (install_mode || upgrade_mode) {
469 plist_t sinf = NULL;
470 plist_t meta = NULL;
471 char *pkgname = NULL;
472 struct stat fst;
473 FILE *f = NULL;
474 uint64_t af = 0;
475 char buf[8192];
476
477 port = 0;
478 if ((lockdownd_start_service(client, "com.apple.afc", &port) !=
479 LOCKDOWN_E_SUCCESS) || !port) {
480 fprintf(stderr, "Could not start com.apple.afc!\n");
481 goto leave_cleanup;
482 }
483
484 lockdownd_client_free(client);
485 client = NULL;
486
487 if (afc_client_new(phone, port, &afc) != INSTPROXY_E_SUCCESS) {
488 fprintf(stderr, "Could not connect to AFC!\n");
489 goto leave_cleanup;
490 }
491
492 if (stat(appid, &fst) != 0) {
493 fprintf(stderr, "ERROR: stat: %s: %s\n", appid, strerror(errno));
494 goto leave_cleanup;
495 }
496
497 /* open install package */
498 int errp = 0;
499 struct zip *zf = zip_open(appid, 0, &errp);
500 if (!zf) {
501 fprintf(stderr, "ERROR: zip_open: %s: %d\n", appid, errp);
502 goto leave_cleanup;
503 }
504
505 /* extract iTunesMetadata.plist from package */
506 char *zbuf = NULL;
507 uint32_t len = 0;
508 if (zip_f_get_contents(zf, "iTunesMetadata.plist", 0, &zbuf, &len) < 0) {
509 zip_unchange_all(zf);
510 zip_close(zf);
511 goto leave_cleanup;
512 }
513 meta = plist_new_data(zbuf, len);
514 free(zbuf);
515
516 /* we need to get the CFBundleName first */
517 plist_t info = NULL;
518 zbuf = NULL;
519 len = 0;
520 if (zip_f_get_contents(zf, "Info.plist", ZIP_FL_NODIR, &zbuf, &len) < 0) {
521 zip_unchange_all(zf);
522 zip_close(zf);
523 goto leave_cleanup;
524 }
525 if (memcmp(zbuf, "bplist00", 8) == 0) {
526 plist_from_bin(zbuf, len, &info);
527 } else {
528 plist_from_xml(zbuf, len, &info);
529 }
530 free(zbuf);
531
532 if (!info) {
533 fprintf(stderr, "Could not parse Info.plist!\n");
534 zip_unchange_all(zf);
535 zip_close(zf);
536 goto leave_cleanup;
537 }
538
539 char *bundlename = NULL;
540
541 plist_t bname = plist_dict_get_item(info, "CFBundleName");
542 if (bname) {
543 plist_get_string_val(bname, &bundlename);
544 }
545 plist_free(info);
546
547 if (!bundlename) {
548 fprintf(stderr, "Could not determine CFBundleName!\n");
549 zip_unchange_all(zf);
550 zip_close(zf);
551 goto leave_cleanup;
552 }
553
554 char *sinfname = NULL;
555 if (asprintf(&sinfname, "Payload/%s.app/SC_Info/%s.sinf", bundlename, bundlename) < 0) {
556 fprintf(stderr, "Out of memory!?\n");
557 goto leave_cleanup;
558 }
559 free(bundlename);
560
561 /* extract .sinf from package */
562 zbuf = NULL;
563 len = 0;
564 if (zip_f_get_contents(zf, sinfname, 0, &zbuf, &len) == 0) {
565 sinf = plist_new_data(zbuf, len);
566 }
567 free(sinfname);
568 if (zbuf) {
569 free(zbuf);
570 }
571
572 zip_unchange_all(zf);
573 zip_close(zf);
574
575 /* copy archive to device */
576 f = fopen(appid, "r");
577 if (!f) {
578 fprintf(stderr, "fopen: %s: %s\n", appid, strerror(errno));
579 goto leave_cleanup;
580 }
581
582 pkgname = NULL;
583 if (asprintf(&pkgname, "%s/%s", PKG_PATH, basename(appid)) < 0) {
584 fprintf(stderr, "Out of memory!?\n");
585 goto leave_cleanup;
586 }
587
588 printf("Copying '%s' --> '%s'\n", appid, pkgname);
589
590 char **strs = NULL;
591 if (afc_get_file_info(afc, PKG_PATH, &strs) != AFC_E_SUCCESS) {
592 if (afc_make_directory(afc, PKG_PATH) != AFC_E_SUCCESS) {
593 fprintf(stderr, "WARNING: Could not create directory '%s' on device!\n", PKG_PATH);
594 }
595 }
596 if (strs) {
597 int i = 0;
598 while (strs[i]) {
599 free(strs[i]);
600 i++;
601 }
602 free(strs);
603 }
604
605 if ((afc_file_open(afc, pkgname, AFC_FOPEN_WRONLY, &af) !=
606 AFC_E_SUCCESS) || !af) {
607 fclose(f);
608 fprintf(stderr, "afc_file_open on '%s' failed!\n", pkgname);
609 free(pkgname);
610 goto leave_cleanup;
611 }
612
613 size_t amount = 0;
614 do {
615 amount = fread(buf, 1, sizeof(buf), f);
616 if (amount > 0) {
617 uint32_t written, total = 0;
618 while (total < amount) {
619 written = 0;
620 if (afc_file_write(afc, af, buf, amount, &written) !=
621 AFC_E_SUCCESS) {
622 fprintf(stderr, "AFC Write error!\n");
623 break;
624 }
625 total += written;
626 }
627 if (total != amount) {
628 fprintf(stderr, "Error: wrote only %d of %d\n", total,
629 amount);
630 afc_file_close(afc, af);
631 fclose(f);
632 free(pkgname);
633 goto leave_cleanup;
634 }
635 }
636 }
637 while (amount > 0);
638
639 afc_file_close(afc, af);
640 fclose(f);
641
642 printf("done.\n");
643
644 /* perform installation or upgrade */
645 if (install_mode) {
646 printf("Installing '%s'\n", pkgname);
647 instproxy_install(ipc, pkgname, sinf, meta, status_cb);
648 } else {
649 printf("Upgrading '%s'\n", pkgname);
650 instproxy_upgrade(ipc, pkgname, sinf, meta, status_cb);
651 }
652 free(pkgname);
653 wait_for_op_complete = 1;
654 notification_expected = 1;
655 } else if (uninstall_mode) {
656 instproxy_uninstall(ipc, appid, status_cb);
657 wait_for_op_complete = 1;
658 notification_expected = 1;
659 } else if (list_archives_mode) {
660 int xml_mode = 0;
661 plist_t dict = NULL;
662 plist_t lres = NULL;
663 instproxy_error_t err;
664
665 /* look for options */
666 if (options) {
667 char *opts = strdup(options);
668 char *elem = strtok(opts, ",");
669 while (elem) {
670 if (!strcmp(elem, "xml")) {
671 xml_mode = 1;
672 }
673 elem = strtok(NULL, ",");
674 }
675 }
676
677 err = instproxy_lookup_archives(ipc, &dict);
678 if (err != INSTPROXY_E_SUCCESS) {
679 fprintf(stderr, "ERROR: lookup_archives returned %d\n", err);
680 goto leave_cleanup;
681 }
682 if (!dict) {
683 fprintf(stderr,
684 "ERROR: lookup_archives did not return a plist!?\n");
685 goto leave_cleanup;
686 }
687
688 lres = plist_dict_get_item(dict, "LookupResult");
689 if (!lres || (plist_get_node_type(lres) != PLIST_DICT)) {
690 plist_free(dict);
691 fprintf(stderr, "ERROR: Could not get dict 'LookupResult'\n");
692 goto leave_cleanup;
693 }
694
695 if (xml_mode) {
696 char *xml = NULL;
697 uint32_t len = 0;
698
699 plist_to_xml(lres, &xml, &len);
700 if (xml) {
701 puts(xml);
702 free(xml);
703 }
704 plist_free(dict);
705 goto leave_cleanup;
706 }
707 plist_dict_iter iter = NULL;
708 plist_t node = NULL;
709 char *key = NULL;
710
711 printf("Total: %d archived apps\n", plist_dict_get_size(lres));
712 plist_dict_new_iter(lres, &iter);
713 if (!iter) {
714 plist_free(dict);
715 fprintf(stderr, "ERROR: Could not create plist_dict_iter!\n");
716 goto leave_cleanup;
717 }
718 do {
719 key = NULL;
720 node = NULL;
721 plist_dict_next_item(lres, iter, &key, &node);
722 if (key && (plist_get_node_type(node) == PLIST_DICT)) {
723 char *s_dispName = NULL;
724 char *s_version = NULL;
725 plist_t dispName =
726 plist_dict_get_item(node, "CFBundleDisplayName");
727 plist_t version =
728 plist_dict_get_item(node, "CFBundleVersion");
729 if (dispName) {
730 plist_get_string_val(dispName, &s_dispName);
731 }
732 if (version) {
733 plist_get_string_val(version, &s_version);
734 }
735 if (!s_dispName) {
736 s_dispName = strdup(key);
737 }
738 if (s_version) {
739 printf("%s - %s %s\n", key, s_dispName, s_version);
740 free(s_version);
741 } else {
742 printf("%s - %s\n", key, s_dispName);
743 }
744 free(s_dispName);
745 free(key);
746 }
747 }
748 while (node);
749 plist_free(dict);
750 } else if (archive_mode) {
751 uint32_t opt = INSTPROXY_ARCHIVE_SKIP_UNINSTALL;
752 char *copy_path = NULL;
753 int remove_after_copy = 0;
754 /* look for options */
755 if (options) {
756 char *opts = strdup(options);
757 char *elem = strtok(opts, ",");
758 while (elem) {
759 if (!strcmp(elem, "uninstall")) {
760 opt &= ~INSTPROXY_ARCHIVE_SKIP_UNINSTALL;
761 } else if (!strcmp(elem, "app_only")) {
762 opt |= INSTPROXY_ARCHIVE_APP_ONLY;
763 } else if ((strlen(elem) > 5) && !strncmp(elem, "copy=", 5)) {
764 copy_path = strdup(elem+5);
765 } else if (!strcmp(elem, "remove")) {
766 remove_after_copy = 1;
767 }
768 elem = strtok(NULL, ",");
769 }
770 }
771
772 if (copy_path) {
773 struct stat fst;
774 if (stat(copy_path, &fst) != 0) {
775 fprintf(stderr, "ERROR: stat: %s: %s\n", copy_path, strerror(errno));
776 free(copy_path);
777 goto leave_cleanup;
778 }
779
780 if (!S_ISDIR(fst.st_mode)) {
781 fprintf(stderr, "ERROR: '%s' is not a directory as expected.\n", copy_path);
782 free(copy_path);
783 goto leave_cleanup;
784 }
785
786 port = 0;
787 if ((lockdownd_start_service(client, "com.apple.afc", &port) != LOCKDOWN_E_SUCCESS) || !port) {
788 fprintf(stderr, "Could not start com.apple.afc!\n");
789 free(copy_path);
790 goto leave_cleanup;
791 }
792
793 lockdownd_client_free(client);
794 client = NULL;
795
796 if (afc_client_new(phone, port, &afc) != INSTPROXY_E_SUCCESS) {
797 fprintf(stderr, "Could not connect to AFC!\n");
798 goto leave_cleanup;
799 }
800 }
801
802 instproxy_archive(ipc, appid, opt, status_cb);
803 wait_for_op_complete = 1;
804 if (opt & INSTPROXY_ARCHIVE_SKIP_UNINSTALL) {
805 notification_expected = 0;
806 } else {
807 notification_expected = 1;
808 }
809
810 do_wait_when_needed();
811
812 if (copy_path) {
813 if (err_occured) {
814 afc_client_free(afc);
815 afc = NULL;
816 goto leave_cleanup;
817 }
818 FILE *f = NULL;
819 uint64_t af = 0;
820 /* local filename */
821 char *localfile = NULL;
822 if (asprintf(&localfile, "%s/%s.ipa", copy_path, appid) < 0) {
823 fprintf(stderr, "Out of memory!?\n");
824 goto leave_cleanup;
825 }
826 free(copy_path);
827
828 f = fopen(localfile, "w");
829 if (!f) {
830 fprintf(stderr, "ERROR: fopen: %s: %s\n", localfile, strerror(errno));
831 free(localfile);
832 goto leave_cleanup;
833 }
834
835 /* remote filename */
836 char *remotefile = NULL;
837 if (asprintf(&remotefile, "%s/%s.zip", APPARCH_PATH, appid) < 0) {
838 fprintf(stderr, "Out of memory!?\n");
839 goto leave_cleanup;
840 }
841
842 uint32_t fsize = 0;
843 char **fileinfo = NULL;
844 if ((afc_get_file_info(afc, remotefile, &fileinfo) != AFC_E_SUCCESS) || !fileinfo) {
845 fprintf(stderr, "ERROR getting AFC file info for '%s' on device!\n", remotefile);
846 fclose(f);
847 free(remotefile);
848 free(localfile);
849 goto leave_cleanup;
850 }
851
852 int i;
853 for (i = 0; fileinfo[i]; i+=2) {
854 if (!strcmp(fileinfo[i], "st_size")) {
855 fsize = atoi(fileinfo[i+1]);
856 break;
857 }
858 }
859 i = 0;
860 while (fileinfo[i]) {
861 free(fileinfo[i]);
862 i++;
863 }
864 free(fileinfo);
865
866 if (fsize == 0) {
867 fprintf(stderr, "Hm... remote file length could not be determined. Cannot copy.\n");
868 fclose(f);
869 free(remotefile);
870 free(localfile);
871 goto leave_cleanup;
872 }
873
874 if ((afc_file_open(afc, remotefile, AFC_FOPEN_RDONLY, &af) != AFC_E_SUCCESS) || !af) {
875 fclose(f);
876 fprintf(stderr, "ERROR: could not open '%s' on device for reading!\n", remotefile);
877 free(remotefile);
878 free(localfile);
879 goto leave_cleanup;
880 }
881
882 /* copy file over */
883 printf("Copying '%s' --> '%s'\n", remotefile, localfile);
884 free(remotefile);
885 free(localfile);
886
887 uint32_t amount = 0;
888 uint32_t total = 0;
889 char buf[8192];
890
891 do {
892 if (afc_file_read(afc, af, buf, sizeof(buf), &amount) != AFC_E_SUCCESS) {
893 fprintf(stderr, "AFC Read error!\n");
894 break;
895 }
896
897 if (amount > 0) {
898 size_t written = fwrite(buf, 1, amount, f);
899 if (written != amount) {
900 fprintf(stderr, "Error when writing %d bytes to local file!\n", amount);
901 break;
902 }
903 total += written;
904 }
905 } while (amount > 0);
906
907 afc_file_close(afc, af);
908 fclose(f);
909
910 printf("done.\n");
911 if (total != fsize) {
912 fprintf(stderr, "WARNING: remote and local file sizes don't match (%d != %d)\n", fsize, total);
913 if (remove_after_copy) {
914 fprintf(stderr, "NOTE: archive file will NOT be removed from device\n");
915 remove_after_copy = 0;
916 }
917 }
918
919 if (remove_after_copy) {
920 /* remove archive if requested */
921 printf("Removing '%s'\n", appid);
922 archive_mode = 0;
923 remove_archive_mode = 1;
924 free(options);
925 options = NULL;
926 if (LOCKDOWN_E_SUCCESS != lockdownd_client_new(phone, &client)) {
927 fprintf(stderr, "Could not connect to lockdownd. Exiting.\n");
928 goto leave_cleanup;
929 }
930 goto run_again;
931 }
932 }
933 goto leave_cleanup;
934 } else if (restore_mode) {
935 instproxy_restore(ipc, appid, status_cb);
936 wait_for_op_complete = 1;
937 notification_expected = 1;
938 } else if (remove_archive_mode) {
939 instproxy_remove_archive(ipc, appid, status_cb);
940 wait_for_op_complete = 1;
941 } else {
942 printf
943 ("ERROR: no operation selected?! This should not be reached!\n");
944 res = -2;
945 goto leave_cleanup;
946 }
947
948 if (client) {
949 /* not needed anymore */
950 lockdownd_client_free(client);
951 client = NULL;
952 }
953
954 do_wait_when_needed();
955
956 leave_cleanup:
957 if (np) {
958 np_client_free(np);
959 }
960 if (ipc) {
961 instproxy_client_free(ipc);
962 }
963 if (afc) {
964 afc_client_free(afc);
965 }
966 if (client) {
967 lockdownd_client_free(client);
968 }
969 iphone_device_free(phone);
970
971 if (uuid) {
972 free(uuid);
973 }
974 if (appid) {
975 free(appid);
976 }
977 if (options) {
978 free(options);
979 }
980
981 return res;
982}