line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package FTN::Packet; |
2
|
|
|
|
|
|
|
|
3
|
5
|
|
|
5
|
|
130721
|
use strict; |
|
5
|
|
|
|
|
14
|
|
|
5
|
|
|
|
|
196
|
|
4
|
5
|
|
|
5
|
|
28
|
use warnings; |
|
5
|
|
|
|
|
9
|
|
|
5
|
|
|
|
|
182
|
|
5
|
5
|
|
|
5
|
|
29
|
use Carp qw( croak ); |
|
5
|
|
|
|
|
15
|
|
|
5
|
|
|
|
|
10323
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=head1 NAME |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
FTN::Packet - Reading or writing Fidonet Technology Networks (FTN) packets. |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
=head1 VERSION |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
VERSION 0.21 |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
=cut |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
our $VERSION = '0.21'; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
=head1 DESCRIPTION |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
FTN::Packet is a Perl extension for reading or writing Fidonet Technology Networks (FTN) packets. |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=cut |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
require Exporter; |
26
|
|
|
|
|
|
|
require AutoLoader; |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
=head1 EXPORT |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
The following functions are available in this module: read_ftn_packet(), |
31
|
|
|
|
|
|
|
write_ftn_packet(). |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
=cut |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
our @ISA = qw(Exporter AutoLoader); |
36
|
|
|
|
|
|
|
# Items to export into callers namespace by default. Note: do not export |
37
|
|
|
|
|
|
|
# names by default without a very good reason. Use EXPORT_OK instead. |
38
|
|
|
|
|
|
|
# Do not simply export all your public functions/methods/constants. |
39
|
|
|
|
|
|
|
our @EXPORT_OK = qw( &read_ftn_packet &write_ftn_packet |
40
|
|
|
|
|
|
|
); |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
=head1 FUNCTIONS |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
=head2 read_ftn_packet |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
Syntax: $messages = read_ftn_packet($pkt_file); |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
Read the messages in a Fidonet/FTN packet. It is passed the name and path of a |
49
|
|
|
|
|
|
|
Fidonet/FTN packet file. Returns the messages in the packet as a reference to an |
50
|
|
|
|
|
|
|
array of hashes, which can be read as follows: |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
for $i ( 0 .. $#{$messages} ) { |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
print "On message $i"; |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
$msg_area = ${$messages}[i]{area}; |
57
|
|
|
|
|
|
|
$msg_date = ${$messages}[i]{ftscdate}; |
58
|
|
|
|
|
|
|
$msg_tonode = ${$messages}[i]{tonode}; |
59
|
|
|
|
|
|
|
$msg_from = ${$messages}[i]{from}; |
60
|
|
|
|
|
|
|
$msg_to = ${$messages}[i]{to}; |
61
|
|
|
|
|
|
|
$msg_subj = ${$messages}[i]{subj}; |
62
|
|
|
|
|
|
|
$msg_msgid = ${$messages}[i]{msgid}; |
63
|
|
|
|
|
|
|
$msg_replyid = ${$messages}[i]{replyid}; |
64
|
|
|
|
|
|
|
$msg_body = ${$messages}[i]{body}; |
65
|
|
|
|
|
|
|
$msg_ctrl = ${$messages}[i]{ctrlinfo}; |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
# Processing of the contents of the message. |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
=cut |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
############################################### |
74
|
|
|
|
|
|
|
# Read Messages from FTN packet |
75
|
|
|
|
|
|
|
############################################### |
76
|
|
|
|
|
|
|
sub read_ftn_packet { |
77
|
|
|
|
|
|
|
|
78
|
4
|
|
|
4
|
1
|
4707
|
my ($packet_file) = @_; |
79
|
|
|
|
|
|
|
|
80
|
4
|
|
|
|
|
13
|
my ($packet_version,$origin_node,$destination_node,$origin_net,$destination_net,$attribute,$cost,$buffer); |
81
|
0
|
|
|
|
|
0
|
my ($separator, $s, $date_time, $to, $from, $subject, $area, @lines, @kludges, $PKT, |
82
|
|
|
|
|
|
|
$from_node, $to_node, @messages, $message_body, $message_id, $reply_id, $origin, |
83
|
|
|
|
|
|
|
$mailer, $seen_by, $i, $k); |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
# "$PKT" is a file pointer to the packet file being read |
86
|
4
|
50
|
|
|
|
183
|
open( $PKT, q{<}, $packet_file ) or croak("Problem opening packet file: $packet_file"); |
87
|
4
|
|
|
|
|
12
|
binmode($PKT); |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
# Ignore packet header |
90
|
4
|
|
|
|
|
94
|
read($PKT,$buffer,58); |
91
|
|
|
|
|
|
|
|
92
|
4
|
|
|
|
|
19
|
while (!eof($PKT)) { |
93
|
|
|
|
|
|
|
|
94
|
8
|
100
|
|
|
|
57
|
last if (read($PKT, $buffer, 14) != 14); |
95
|
|
|
|
|
|
|
|
96
|
4
|
|
|
|
|
68
|
($packet_version, $origin_node, $destination_node, $origin_net, $destination_net, $attribute, $cost) = unpack("SSSSSSS",$buffer); |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
# not used for anything yet - 8/26/01 rjc |
99
|
4
|
|
|
|
|
15
|
undef $packet_version; |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
# not used for anything yet - 8/26/01 rjc |
102
|
4
|
|
|
|
|
8
|
undef $attribute; |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
# not used for anything yet - 12/15/01 rjc |
105
|
4
|
|
|
|
|
7
|
undef $cost; |
106
|
|
|
|
|
|
|
|
107
|
4
|
|
|
|
|
10
|
$separator = $/; |
108
|
4
|
|
|
|
|
41
|
local $/ = "\0"; |
109
|
|
|
|
|
|
|
|
110
|
4
|
|
|
|
|
20
|
$date_time = <$PKT>; |
111
|
4
|
50
|
|
|
|
26
|
if (length($date_time) > 20) { |
112
|
0
|
|
|
|
|
0
|
$to = substr($date_time,20); |
113
|
|
|
|
|
|
|
} else { |
114
|
4
|
|
|
|
|
12
|
$to = <$PKT>; |
115
|
|
|
|
|
|
|
} |
116
|
4
|
|
|
|
|
10
|
$from = <$PKT>; |
117
|
4
|
|
|
|
|
11
|
$subject = <$PKT>; |
118
|
|
|
|
|
|
|
|
119
|
4
|
|
|
|
|
29
|
$to =~ tr/\200-\377/\0-\177/; # mask hi-bit characters |
120
|
4
|
|
|
|
|
9
|
$to =~ tr/\0-\037/\040-\077/; # mask control characters |
121
|
4
|
|
|
|
|
11
|
$from =~ tr/\200-\377/\0-\177/; # mask hi-bit characters |
122
|
4
|
|
|
|
|
10
|
$from =~ tr/\0-\037/\040-\077/; # mask control characters |
123
|
4
|
|
|
|
|
10
|
$subject =~ tr/\0-\037/\040-\077/; # mask control characters |
124
|
|
|
|
|
|
|
|
125
|
4
|
|
|
|
|
13
|
$s = <$PKT>; |
126
|
4
|
|
|
|
|
236
|
local $/ = $separator; |
127
|
|
|
|
|
|
|
|
128
|
4
|
|
|
|
|
14
|
$s =~ s/\x8d/\r/g; |
129
|
4
|
|
|
|
|
35
|
@lines = split(/\r/,$s); |
130
|
|
|
|
|
|
|
|
131
|
4
|
|
|
|
|
10
|
undef $s; |
132
|
|
|
|
|
|
|
|
133
|
4
|
50
|
|
|
|
14
|
next if ($#lines < 0); |
134
|
|
|
|
|
|
|
|
135
|
4
|
|
|
|
|
10
|
$area = shift(@lines); |
136
|
4
|
|
|
|
|
10
|
$_ = $area; |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
# default netmail area name |
139
|
4
|
100
|
|
|
|
26
|
$area ="NETMAIL" if /\//i; |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
# strip "area:" |
142
|
4
|
|
|
|
|
167
|
$area =~ s/.*://; |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
# Force upper case ??? |
145
|
4
|
|
|
|
|
11
|
$area =~ tr/a-z/A-Z/; |
146
|
|
|
|
|
|
|
|
147
|
4
|
|
|
|
|
14
|
@kludges = (); |
148
|
|
|
|
|
|
|
|
149
|
4
|
|
|
|
|
14
|
for ($i = $k = 0; $i <= $#lines; $i++) { |
150
|
|
|
|
|
|
|
|
151
|
20
|
100
|
|
|
|
69
|
if ($lines[$i] =~ /^\001/) { |
152
|
4
|
|
|
|
|
24
|
$kludges[$k++] = splice(@lines,$i,1); |
153
|
4
|
|
|
|
|
13
|
redo; |
154
|
|
|
|
|
|
|
} |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
4
|
|
|
|
|
7
|
for (;;) { |
158
|
8
|
|
|
|
|
17
|
$_ = pop(@lines); |
159
|
8
|
100
|
|
|
|
29
|
last if ($_ eq ""); |
160
|
6
|
100
|
|
|
|
27
|
if (/ \* origin: /i) { |
161
|
2
|
|
|
|
|
7
|
$origin = substr($_,11); |
162
|
2
|
|
|
|
|
6
|
last; |
163
|
|
|
|
|
|
|
} |
164
|
4
|
50
|
|
|
|
14
|
if (/---/) { |
165
|
0
|
|
|
|
|
0
|
$mailer = $_; |
166
|
|
|
|
|
|
|
} |
167
|
4
|
50
|
|
|
|
16
|
if (/seen-by/i) { |
168
|
0
|
|
|
|
|
0
|
$seen_by=$_; |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
4
|
50
|
|
|
|
13
|
if ( ! $mailer ) { |
173
|
4
|
|
|
|
|
7
|
$mailer = "---"; |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
4
|
50
|
|
|
|
12
|
if ($#lines < 0) { |
177
|
0
|
|
|
|
|
0
|
@lines = ("[empty message]"); |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
# get message body, ensuring that it starts empty |
181
|
4
|
|
|
|
|
7
|
$message_body = ""; |
182
|
|
|
|
|
|
|
|
183
|
4
|
|
|
|
|
9
|
foreach my $s (@lines) { |
184
|
8
|
|
|
|
|
14
|
$s =~ tr/\0-\037/\040-\077/; # mask control characters |
185
|
8
|
|
|
|
|
47
|
$s =~ s/\s+$//; |
186
|
8
|
|
|
|
|
14
|
$s=~tr/^\*/ /; |
187
|
8
|
|
|
|
|
32
|
$message_body .= "$s\n"; |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
|
190
|
4
|
50
|
|
|
|
22
|
$message_body .= "$mailer\n" if ($mailer); |
191
|
4
|
100
|
|
|
|
21
|
$message_body .= " * Origin: $origin\n" if ($origin); |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
# get control info, ensuring that it starts empty |
194
|
4
|
|
|
|
|
8
|
my $control_info = ""; |
195
|
4
|
50
|
|
|
|
23
|
$control_info .= "$seen_by\n" if ($seen_by); |
196
|
4
|
|
|
|
|
7
|
foreach my $c (@kludges) { |
197
|
4
|
|
|
|
|
28
|
$c =~ s/^\001//; |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
# If kludge starts with "MSGID:", stick that in a special |
200
|
|
|
|
|
|
|
# variable. |
201
|
4
|
50
|
|
|
|
30
|
if ( substr($c, 0, 6) eq "MSGID:" ) { |
202
|
4
|
|
|
|
|
12
|
$message_id = substr($c, 7); |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
|
205
|
4
|
|
|
|
|
17
|
$control_info .= "$c\n"; |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
|
208
|
4
|
50
|
|
|
|
12
|
if ( ! $message_id) { |
209
|
0
|
|
|
|
|
0
|
$message_id = "message id not available"; |
210
|
|
|
|
|
|
|
} |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
# get replyid from kludges? same way as get seenby? |
213
|
4
|
|
|
|
|
10
|
$reply_id = "reply id not available"; |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
# need to pull zone num's from pkt instead of defaulting 1 |
216
|
4
|
|
|
|
|
19
|
$from_node = "1:$origin_net/$origin_node\n"; |
217
|
4
|
|
|
|
|
14
|
$to_node = "1:$destination_net/$destination_node\n"; |
218
|
|
|
|
|
|
|
|
219
|
4
|
|
|
|
|
59
|
my %message_info = ( |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
area => $area, |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
ftscdate => $date_time, |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
## not useing this yet... |
226
|
|
|
|
|
|
|
#cost => $cost, |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
fromnode => $from_node, |
229
|
|
|
|
|
|
|
tonode => $to_node, |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
from => $from, |
232
|
|
|
|
|
|
|
to => $to, |
233
|
|
|
|
|
|
|
subj => $subject, |
234
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
msgid => $message_id, |
236
|
|
|
|
|
|
|
replyid => $reply_id, |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
body => $message_body, |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
ctrlinfo => $control_info |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
); |
243
|
|
|
|
|
|
|
|
244
|
4
|
|
|
|
|
28
|
push(@messages, \%message_info); |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
} # end while |
247
|
|
|
|
|
|
|
|
248
|
4
|
|
|
|
|
69
|
return \@messages; |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
} # end sub read_ftn_packet |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
=head2 write_ftn_packet |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
Syntax: write_ftn_packet($OutDir, \%packet_info, \@messages); |
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
Create a Fidonet/FTN packet, where: |
258
|
|
|
|
|
|
|
$OutDir is the directory where the packet is to be created |
259
|
|
|
|
|
|
|
\%packet_info is a reference to a hash containing the packet header |
260
|
|
|
|
|
|
|
\@messages is reference to an array of references to hashes containing the messages. |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
=cut |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
sub write_ftn_packet { |
265
|
|
|
|
|
|
|
|
266
|
0
|
|
|
0
|
1
|
|
my ($OutDir, $packet_info, $messages) = @_; |
267
|
|
|
|
|
|
|
|
268
|
0
|
|
|
|
|
|
my ($packet_file, $PKT, @lines, $serialno, $buffer, $nmsgs, $i, $k, $message_ref); |
269
|
|
|
|
|
|
|
|
270
|
0
|
|
|
|
|
|
my $EOL = "\n\r"; |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
# This part is a definition of an FTN Packet format per FTS-0001 |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
# PKT Header; initialized variable are constants; last comments are |
275
|
|
|
|
|
|
|
# in pack() notation |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
# ${$packet_info}{OrgNode} # S |
278
|
|
|
|
|
|
|
# ${$packet_info}{DestNode} # S |
279
|
0
|
|
|
|
|
|
my ($year, $month, $day, $hour, $minutes, $seconds); # SSSSSS |
280
|
0
|
|
|
|
|
|
my $Baud = 0; # S |
281
|
0
|
|
|
|
|
|
my $packet_version = 2; # S Type 2 packet |
282
|
|
|
|
|
|
|
# ${$packet_info}{OrgNet} # S |
283
|
|
|
|
|
|
|
# ${$packet_info}{DestNet} # S |
284
|
0
|
|
|
|
|
|
my $ProdCode = 0x1CFF; # S product code = 1CFF |
285
|
|
|
|
|
|
|
# ${$packet_info}{PassWord} # a8 |
286
|
|
|
|
|
|
|
# ${$packet_info}{OrgZone} # S |
287
|
|
|
|
|
|
|
# ${$packet_info}{DestZone} # S |
288
|
0
|
|
|
|
|
|
my $AuxNet = ${$packet_info}{OrgNet}; # S |
|
0
|
|
|
|
|
|
|
289
|
0
|
|
|
|
|
|
my $CapWord = 0x100; # S capability word: Type 2+ |
290
|
0
|
|
|
|
|
|
my $ProdCode2 = 0; # S ? |
291
|
0
|
|
|
|
|
|
my $CapWord2 = 1; # S byte swapped cap. word |
292
|
|
|
|
|
|
|
# ${$packet_info}{OrgZone} # S (repeat) |
293
|
|
|
|
|
|
|
# ${$packet_info}{DestZone} # S (repeat) |
294
|
|
|
|
|
|
|
# ${$packet_info}{OrgPoint} # S |
295
|
|
|
|
|
|
|
# config file for node info? |
296
|
|
|
|
|
|
|
# ${$packet_info}{DestPoint} # S |
297
|
0
|
|
|
|
|
|
my $ProdSpec = 0; # L ? |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
# MSG Header; duplicated variables are shown as comments to indicate |
300
|
|
|
|
|
|
|
# the MSG Header structure |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
# $packet_version # S (repeat) |
303
|
|
|
|
|
|
|
# ${$packet_info}{OrgNode} # S (repeat) |
304
|
|
|
|
|
|
|
# ${$packet_info}{DestNode} # S (repeat) |
305
|
|
|
|
|
|
|
# ${$packet_info}{OrgNet} # S (repeat) |
306
|
|
|
|
|
|
|
# ${$packet_info}{DestNet} # S (repeat) |
307
|
0
|
|
|
|
|
|
my $attribute = 0; # S |
308
|
0
|
|
|
|
|
|
my $Cost = 0; # S |
309
|
|
|
|
|
|
|
# ${$message_ref}{DateTime} # a20 (this is a local()) |
310
|
|
|
|
|
|
|
# ${$message_ref}{To} # a? (36 max) |
311
|
|
|
|
|
|
|
# ${$message_ref}{From} # a? (36 max) |
312
|
|
|
|
|
|
|
# ${$message_ref}{Subj} # a? (72 max) |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
#"AREA: " # c6 } |
315
|
|
|
|
|
|
|
# ${$packet_info}{Area} # a? (max?) } all this is actually part |
316
|
|
|
|
|
|
|
#possible kludges go here. 0x010x0D } of the TEXT postions |
317
|
|
|
|
|
|
|
#TEXT goes here. (ends with 2 0x0D's ???) } |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
# ${$packet_info}{TearLine} |
320
|
0
|
|
|
|
|
|
my $Origin = " * Origin: ${$packet_info}{Origin} (${$packet_info}{OrgZone}:${$packet_info}{OrgNet}/${$packet_info}{OrgNode}.1)$EOL"; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
321
|
0
|
|
|
|
|
|
my $seen_by = "SEEN-BY: ${$packet_info}{OrgNet}/${$packet_info}{OrgNode}$EOL"; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
322
|
0
|
|
|
|
|
|
my $Path = "\1PATH: ${$packet_info}{OrgNet}/${$packet_info}{OrgNode}$EOL\0"; # note the \0 in $Path |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
# repeat MSG Headers/TEXT |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
# null (S) to mark done |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
# this is where a loop would go if more than one feed |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
# PKT name as per FTS |
331
|
0
|
|
|
|
|
|
($seconds, $minutes, $hour, $day, $month, $year) = localtime(); |
332
|
0
|
|
|
|
|
|
$year += 1900; |
333
|
|
|
|
|
|
|
|
334
|
0
|
|
|
|
|
|
$packet_file = sprintf("%s/%02d%02d%02d%02d.pkt",$OutDir,$day,$hour,$minutes,$seconds); |
335
|
|
|
|
|
|
|
|
336
|
0
|
0
|
|
|
|
|
open( $PKT, q{>}, "$packet_file" ) or croak('Cannot open FTN packet file for writing.'); |
337
|
|
|
|
|
|
|
|
338
|
0
|
|
|
|
|
|
binmode($PKT); |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
# write packet header |
341
|
0
|
|
|
|
|
|
$buffer = pack("SSSSSSSSSSSSSa8SSSSSSSSSSL", |
342
|
0
|
|
|
|
|
|
${$packet_info}{OrgNode}, ${$packet_info}{DestNode}, |
|
0
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
$year, $month, $day, $hour, $minutes, $seconds, |
344
|
|
|
|
|
|
|
$Baud, $packet_version, |
345
|
0
|
|
|
|
|
|
${$packet_info}{OrgNet}, ${$packet_info}{DestNet}, |
|
0
|
|
|
|
|
|
|
346
|
0
|
|
|
|
|
|
$ProdCode, ${$packet_info}{PassWord}, |
347
|
0
|
|
|
|
|
|
${$packet_info}{OrgZone}, ${$packet_info}{DestZone}, $AuxNet, |
|
0
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
$CapWord, $ProdCode2, $CapWord2, |
349
|
0
|
|
|
|
|
|
${$packet_info}{OrgZone}, ${$packet_info}{DestZone}, |
|
0
|
|
|
|
|
|
|
350
|
0
|
|
|
|
|
|
${$packet_info}{OrgPoint}, ${$packet_info}{DestPoint}, $ProdSpec); |
|
0
|
|
|
|
|
|
|
351
|
0
|
|
|
|
|
|
syswrite($PKT,$buffer,58); |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
# needs to iterate over the array of hashes representing the messages |
354
|
0
|
|
|
|
|
|
foreach my $message_ref ( @{$messages} ) { |
|
0
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
#while ( @{$messages} > 0) { |
356
|
|
|
|
|
|
|
#while ( @{$messages} ) { |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
## get next message hash reference |
359
|
|
|
|
|
|
|
#$message_ref = pop(@{$messages}); |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
# get text body, translate LFs to CRs |
362
|
|
|
|
|
|
|
|
363
|
0
|
|
|
|
|
|
@lines = ${$message_ref}{Body}; |
|
0
|
|
|
|
|
|
|
364
|
0
|
|
|
|
|
|
@lines = grep { s/\n/\r/ } @lines; |
|
0
|
|
|
|
|
|
|
365
|
|
|
|
|
|
|
|
366
|
|
|
|
|
|
|
# kill leading blank lines |
367
|
|
|
|
|
|
|
|
368
|
0
|
|
|
|
|
|
shift(@lines) while ($lines[0] eq "\n"); |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
# informative only |
371
|
0
|
|
|
|
|
|
++$nmsgs; |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
# write message to $PKT file |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
# Write Message Header |
376
|
0
|
|
|
|
|
|
$buffer = pack("SSSSSSSa20", |
377
|
0
|
|
|
|
|
|
$packet_version,${$packet_info}{OrgNode},${$packet_info}{DestNode},${$packet_info}{OrgNet}, |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
378
|
0
|
|
|
|
|
|
${$packet_info}{DestNet},$attribute,$Cost,${$message_ref}{DateTime}); |
|
0
|
|
|
|
|
|
|
379
|
0
|
|
|
|
|
|
print $PKT $buffer; |
380
|
|
|
|
|
|
|
|
381
|
0
|
|
|
|
|
|
print $PKT "${$message_ref}{To}\0"; |
|
0
|
|
|
|
|
|
|
382
|
0
|
|
|
|
|
|
print $PKT "${$message_ref}{From}\0"; |
|
0
|
|
|
|
|
|
|
383
|
0
|
|
|
|
|
|
print $PKT "${$message_ref}{Subj}\0"; |
|
0
|
|
|
|
|
|
|
384
|
0
|
|
|
|
|
|
print $PKT "AREA: ${$packet_info}{Area}$EOL"; # note: CR not nul |
|
0
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
|
386
|
0
|
|
|
|
|
|
$serialno = unpack("%16C*",join('',@lines)); |
387
|
0
|
|
|
|
|
|
$serialno = sprintf("%lx",$serialno + time); |
388
|
0
|
|
|
|
|
|
print $PKT "\1MSGID: ${$packet_info}{OrgZone}:${$packet_info}{OrgNet}/${$packet_info}{OrgNode}.${$packet_info}{OrgPoint} $serialno$EOL"; |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
|
390
|
0
|
|
|
|
|
|
print $PKT @lines; |
391
|
0
|
|
|
|
|
|
print $PKT $EOL,${$packet_info}{TearLine},$Origin,$seen_by,$Path; |
|
0
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
# all done with array (frees mem?) |
394
|
0
|
|
|
|
|
|
@lines = (); |
395
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
} |
397
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
# indicates no more messages |
399
|
0
|
|
|
|
|
|
print $PKT "\0\0"; |
400
|
|
|
|
|
|
|
|
401
|
0
|
|
|
|
|
|
close($PKT); |
402
|
|
|
|
|
|
|
|
403
|
0
|
|
|
|
|
|
return 0; |
404
|
|
|
|
|
|
|
} |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
1; |
407
|
|
|
|
|
|
|
__END__ |